/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/

"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __accessCheck = (obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
  __accessCheck(obj, member, "read from private field");
  return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
  if (member.has(obj))
    throw 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);
  return value;
};

// src/main.ts
var main_exports = {};
__export(main_exports, {
  default: () => CalloutManagerPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian18 = require("obsidian");

// node_modules/obsidian-extra/dist/esm/functions/getFloatingWindows.js
function getFloatingWindows(app2) {
  var _a, _b, _c, _d;
  return (_d = (_c = (_b = (_a = app2 === null || app2 === void 0 ? void 0 : app2.workspace) === null || _a === void 0 ? void 0 : _a.floatingSplit) === null || _b === void 0 ? void 0 : _b.children) === null || _c === void 0 ? void 0 : _c.map((split) => split.win)) !== null && _d !== void 0 ? _d : [];
}

// node_modules/obsidian-extra/dist/esm/functions/getCurrentThemeID.js
function getCurrentThemeID(app2) {
  const theme = app2.customCss.theme;
  return theme === "" ? null : theme;
}

// node_modules/obsidian-extra/dist/esm/functions/getCurrentColorScheme.js
function getCurrentThemeID2(app2) {
  const { body } = app2.workspace.containerEl.doc;
  return body.classList.contains("theme-dark") ? "dark" : "light";
}

// node_modules/obsidian-extra/dist/esm/functions/getThemeManifest.js
function getThemeManifest(app2, themeID) {
  const manifests = app2.customCss.themes;
  if (!Object.prototype.hasOwnProperty.call(manifests, themeID)) {
    return null;
  }
  return manifests[themeID];
}

// node_modules/obsidian-extra/dist/esm/functions/isThemeInstalled.js
function isThemeInstalled(app2, themeID) {
  return getThemeManifest(app2, themeID) !== null;
}

// node_modules/obsidian-extra/dist/esm/functions/getThemeStyleElement.js
function getThemeStyleElement(app2) {
  const currentTheme = getCurrentThemeID(app2);
  if (currentTheme == null || !isThemeInstalled(app2, currentTheme)) {
    return null;
  }
  return app2.customCss.styleEl;
}

// node_modules/obsidian-extra/dist/esm/functions/isSnippetEnabled.js
function isSnippetEnabled(app2, snippetID) {
  return app2.customCss.enabledSnippets.has(snippetID);
}

// node_modules/obsidian-extra/dist/esm/functions/fetchObsidianStyles.js
var import_obsidian = require("obsidian");

// node_modules/obsidian-extra/dist/esm/internal/utils/versionCompare.js
function versionCompare(a, b) {
  const aParts = a.split(".").map((n) => parseInt(n, 10));
  const bParts = b.split(".").map((n) => parseInt(n, 10));
  const partsSize = Math.max(aParts.length, bParts.length);
  arrayPadEnd(aParts, partsSize, 0);
  arrayPadEnd(bParts, partsSize, 0);
  for (let i = 0; i < partsSize; i++) {
    if (aParts[i] < bParts[i])
      return -1;
    if (aParts[i] > bParts[i])
      return 1;
  }
  return 0;
}
function arrayPadEnd(arr, length, fill) {
  const missing = length - arr.length;
  if (missing > 0) {
    arr.push(...new Array(missing).fill(fill));
  }
}

// node_modules/obsidian-extra/dist/esm/functions/fetchObsidianStyles.js
var __awaiter = function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
function fetchObsidianStyles(app2) {
  var _a;
  return __awaiter(this, void 0, void 0, function* () {
    if (versionCompare(import_obsidian.apiVersion, "1.1.15") > 0) {
      throw new Error(`[obsidian-extra]: Obsidian ${import_obsidian.apiVersion} has not been tested with this function`);
    }
    try {
      const electron = (_a = globalThis.electron) !== null && _a !== void 0 ? _a : require("electron");
      if (electron == null) {
        throw new Error("Unable to get electron module from web renderer process");
      }
      const fs = require("fs/promises");
      if ((fs === null || fs === void 0 ? void 0 : fs.readFile) == null) {
        throw new Error("Unable to get fs module from web renderer process");
      }
      const resources = electron.ipcRenderer.sendSync("resources");
      return yield fs.readFile(`${resources}/app.css`, "utf8");
    } catch (ex) {
      throw new Error(`[obsidian-extra]: Could not get Obsidian styles: ${ex}`);
    }
  });
}

// node_modules/obsidian-extra/dist/esm/functions/getInstalledSnippetIDs.js
function getInstalledSnippetIDs(app2) {
  return app2.customCss.snippets;
}

// node_modules/obsidian-extra/dist/esm/functions/getSnippetStyleElements.js
function getSnippetStyleElements(app2) {
  const styleManager = app2.customCss;
  const snippets = getInstalledSnippetIDs(app2);
  const map = /* @__PURE__ */ new Map();
  for (let i = 0, elI = 0; i < snippets.length; i++) {
    const snippetID = styleManager.snippets[i];
    if (isSnippetEnabled(app2, snippetID)) {
      map.set(snippetID, styleManager.extraStyleEls[elI]);
      elI++;
    }
  }
  return map;
}

// node_modules/obsidian-extra/dist/esm/functions/openPluginSettings.js
function openPluginSettings(app2, plugin) {
  var _a, _b;
  const settingManager = app2.setting;
  const pluginId = typeof plugin === "string" ? plugin : plugin.manifest.id;
  if (((_a = settingManager.activeTab) === null || _a === void 0 ? void 0 : _a.id) !== pluginId) {
    settingManager.openTabById("");
  }
  settingManager.open();
  if (((_b = settingManager.activeTab) === null || _b === void 0 ? void 0 : _b.id) !== pluginId) {
    settingManager.openTabById(pluginId);
  }
}

// node_modules/obsidian-extra/dist/esm/functions/createCustomStyleSheet.js
var Counter = Symbol("CustomStylesheet count");
function foreachWindow(app2, fn) {
  fn(app2.workspace.containerEl.doc, true);
  for (const float of getFloatingWindows(app2)) {
    fn(float.document, false);
  }
}
function createCustomStyleSheet(app2, plugin) {
  var _a;
  let result;
  const pl = plugin;
  const plId = plugin.manifest.id;
  const ssId = ((_a = pl[Counter]) !== null && _a !== void 0 ? _a : pl[Counter] = 0).toString();
  pl[Counter]++;
  const styleEl = app2.workspace.containerEl.doc.createElement("style");
  const styleElInFloats = [];
  styleEl.setAttribute("data-source-plugin", plId);
  styleEl.setAttribute("data-source-id", ssId);
  function unapply() {
    styleElInFloats.splice(0, styleElInFloats.length).forEach((el) => el.remove());
    styleEl.detach();
    foreachWindow(app2, (doc) => {
      for (const styleEl2 of Array.from(doc.head.querySelectorAll("style"))) {
        if (result.is(styleEl2)) {
          styleEl2.remove();
        }
      }
    });
  }
  function reapply() {
    unapply();
    foreachWindow(app2, (doc, isFloating) => {
      let lastEl = doc.head.lastElementChild;
      for (let el = lastEl; el != null; el = el.previousElementSibling) {
        lastEl = el;
        if (lastEl.tagName === "STYLE") {
          break;
        }
      }
      if (!isFloating) {
        lastEl === null || lastEl === void 0 ? void 0 : lastEl.insertAdjacentElement("afterend", styleEl);
        return;
      }
      const styleElClone = styleEl.cloneNode(true);
      styleElInFloats.push(styleElClone);
      lastEl === null || lastEl === void 0 ? void 0 : lastEl.insertAdjacentElement("afterend", styleElClone);
    });
  }
  app2.workspace.on("css-change", reapply);
  app2.workspace.on("layout-change", reapply);
  result = Object.freeze(Object.defineProperties(() => {
    unapply();
    app2.workspace.off("css-change", reapply);
    app2.workspace.off("layout-change", reapply);
  }, {
    css: {
      enumerable: true,
      configurable: false,
      get() {
        return styleEl.textContent;
      },
      set(v) {
        styleEl.textContent = v;
        for (const styleEl2 of styleElInFloats) {
          styleEl2.textContent = v;
        }
      }
    },
    is: {
      enumerable: false,
      configurable: false,
      value: (el) => {
        return el.getAttribute("data-source-plugin") === plId && el.getAttribute("data-source-id") === ssId;
      }
    },
    setAttribute: {
      enumerable: false,
      configurable: false,
      value: (attr, value) => {
        if (attr === "data-source-id" || attr === "data-source-plugin") {
          throw new Error(`Cannot change attribute '${attr}' on custom style sheet.`);
        }
        styleEl.setAttribute(attr, value);
        for (const styleEl2 of styleElInFloats) {
          styleEl2.setAttribute(attr, value);
        }
      }
    },
    removeAttribute: {
      enumerable: false,
      configurable: false,
      value: (attr) => {
        if (attr === "data-source-id" || attr === "data-source-plugin") {
          throw new Error(`Cannot remove attribute '${attr}' from custom style sheet.`);
        }
        styleEl.removeAttribute(attr);
        for (const styleEl2 of styleElInFloats) {
          styleEl2.removeAttribute(attr);
        }
      }
    }
  }));
  reapply();
  return result;
}

// src/ui/paned-setting-tab.ts
var import_obsidian3 = require("obsidian");

// node_modules/obsidian-extra/dist/esm/functions/closeSettings.js
function closeSettings(app2) {
  const settingManager = app2.setting;
  settingManager.close();
}

// src/ui/pane-layers.ts
var import_obsidian2 = require("obsidian");
var UIPaneLayers = class {
  constructor(options) {
    this.layers = [];
    this.closeParent = options.close;
    this.navInstance = {
      open: (pane) => this.push(pane),
      close: () => this.pop(),
      replace: (pane) => this.top = pane
    };
  }
  /**
   * Pushes a new pane on top of the stack.
   * The active pane will be suspended.
   *
   * @param pane The pane to push.
   */
  push(pane) {
    const { activePane: oldPane } = this;
    if (oldPane !== void 0) {
      const title = oldPane.title;
      this.layers.push({
        scroll: { top: this.scrollEl.scrollTop, left: this.scrollEl.scrollLeft },
        state: oldPane.suspendState(),
        pane: oldPane,
        title: typeof title === "string" ? title : title.subtitle
      });
      this.setPaneVariables(oldPane, false);
      this.containerEl.empty();
    }
    const newPane = this.activePane = pane;
    this.setPaneVariables(newPane, true);
    newPane.onReady();
    this.doDisplay(true);
    this.scrollEl.scrollTo({ top: 0, left: 0 });
  }
  /**
   * Pops the active pane off the stack.
   * The active pane will be destroyed, and the one underneath it will be restored.
   *
   * @param pane The pane to push.
   */
  pop(options) {
    var _a, _b;
    if (this.activePane === void 0) {
      this.closeParent();
      return void 0;
    }
    const noDisplay = (_a = options == null ? void 0 : options.noDisplay) != null ? _a : false;
    const oldPane = this.activePane;
    const newPane = this.layers.pop();
    this.activePane = void 0;
    this.setPaneVariables(oldPane, false);
    oldPane.onClose((_b = options == null ? void 0 : options.cancelled) != null ? _b : false);
    if (!noDisplay) {
      this.containerEl.empty();
    }
    if (newPane !== void 0) {
      this.activePane = newPane.pane;
      this.setPaneVariables(newPane.pane, true);
      newPane.pane.restoreState(newPane.state);
      if (!noDisplay) {
        this.doDisplay(true);
        this.scrollEl.scrollTo(newPane.scroll);
      }
    }
    return oldPane;
  }
  /**
   * Removes all panes off the stack.
   * All panes will be destroyed.
   *
   * @param pane The pane to push.
   */
  clear(options) {
    const removed = [];
    const opts = {
      noDisplay: true,
      ...options != null ? options : {}
    };
    while (this.activePane !== void 0) {
      removed.push(this.pop(opts));
    }
    return removed;
  }
  /**
   * The top-most (i.e. currently active) pane in the layers.
   */
  get top() {
    return this.activePane;
  }
  set top(pane) {
    const { activePane: oldTop } = this;
    if (oldTop !== void 0) {
      this.setPaneVariables(oldTop, false);
      oldTop.onClose(false);
    }
    const newPane = this.activePane = pane;
    this.setPaneVariables(newPane, true);
    newPane.onReady();
    this.doDisplay(true);
  }
  doDisplay(renderControls) {
    const { activePane, titleEl, navEl, containerEl } = this;
    if (activePane === void 0) {
      return;
    }
    navEl.empty();
    if (this.layers.length > 0) {
      new import_obsidian2.ButtonComponent(this.navEl).setIcon("lucide-arrow-left-circle").setClass("clickable-icon").setTooltip(`Back to ${this.layers[this.layers.length - 1].title}`).onClick(() => this.navInstance.close());
    }
    titleEl.empty();
    const { title } = activePane;
    if (typeof title === "string") {
      titleEl.createEl("h2", { text: title });
    } else {
      titleEl.createEl("h2", { text: title.title });
      titleEl.createEl("h3", { text: title.subtitle });
    }
    if (renderControls) {
      this.controlsEl.empty();
      activePane.displayControls();
    }
    containerEl.empty();
    activePane.display();
  }
  setPaneVariables(pane, attached) {
    const notAttachedError = () => {
      throw new Error("Not attached");
    };
    Object.defineProperties(pane, {
      nav: {
        configurable: true,
        enumerable: true,
        get: attached ? () => this.navInstance : notAttachedError
      },
      containerEl: {
        configurable: true,
        enumerable: true,
        get: attached ? () => this.containerEl : notAttachedError
      },
      controlsEl: {
        configurable: true,
        enumerable: true,
        get: attached ? () => this.controlsEl : notAttachedError
      }
    });
  }
};

// src/ui/paned-setting-tab.ts
var UISettingTab = class extends import_obsidian3.PluginSettingTab {
  constructor(plugin, createDefault) {
    super(plugin.app, plugin);
    this.plugin = plugin;
    this.createDefault = createDefault;
    this.initLayer = null;
    this.layers = new UIPaneLayers({
      close: () => closeSettings(this.app)
    });
  }
  openWithPane(pane) {
    this.initLayer = pane;
    openPluginSettings(this.plugin.app, this.plugin);
  }
  /** @override */
  hide() {
    this.initLayer = null;
    this.layers.clear();
    super.hide();
  }
  display() {
    var _a;
    const { containerEl, layers } = this;
    containerEl.empty();
    containerEl.classList.add("calloutmanager-setting-tab", "calloutmanager-pane");
    const headerEl = containerEl.createDiv({ cls: "calloutmanager-setting-tab-header" });
    layers.navEl = headerEl.createDiv({ cls: "calloutmanager-setting-tab-nav" });
    layers.titleEl = headerEl.createDiv({ cls: "calloutmanager-setting-tab-title" });
    const controlsEl = headerEl.createDiv({ cls: "calloutmanager-setting-tab-controls" });
    layers.controlsEl = controlsEl.createDiv();
    layers.scrollEl = containerEl.createDiv({
      cls: "calloutmanager-setting-tab-viewport vertical-tab-content"
    });
    layers.containerEl = layers.scrollEl.createDiv({ cls: "calloutmanager-setting-tab-content" });
    controlsEl.createDiv({ cls: "modal-close-button" }, (closeButtonEl) => {
      closeButtonEl.addEventListener("click", (ev) => {
        if (!ev.isTrusted)
          return;
        closeSettings(this.app);
      });
    });
    layers.clear();
    const initLayer = (_a = this.initLayer) != null ? _a : this.createDefault();
    this.initLayer = null;
    layers.top = initLayer;
  }
};

// src/api-v1.ts
var import_obsidian5 = require("obsidian");

// src/util/color.ts
function toHSV(color) {
  if ("h" in color && "s" in color && "v" in color)
    return color;
  const rFloat = color.r / 255;
  const gFloat = color.g / 255;
  const bFloat = color.b / 255;
  const cmax = Math.max(rFloat, gFloat, bFloat);
  const cmin = Math.min(rFloat, gFloat, bFloat);
  const delta = cmax - cmin;
  let h = 0;
  if (cmax !== cmin) {
    switch (cmax) {
      case rFloat:
        h = (60 * ((gFloat - bFloat) / delta) + 360) % 360;
        break;
      case gFloat:
        h = (60 * ((bFloat - rFloat) / delta) + 120) % 360;
        break;
      case bFloat:
        h = (60 * ((rFloat - gFloat) / delta) + 240) % 360;
        break;
    }
  }
  const s = cmax === 0 ? 0 : delta / cmax * 100;
  const v = cmax * 100;
  const hsv = { h, s, v };
  if ("a" in color) {
    hsv.a = color.a / 255 * 100;
  }
  return hsv;
}
function toHexRGB(color) {
  const parts = [color.r, color.g, color.b, ..."a" in color ? [color.a] : []];
  return parts.map((c) => c.toString(16).padStart(2, "0")).join("");
}
var REGEX_RGB = /^\s*rgba?\(\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?\s*)\)\s*$/i;
function parseColorRGB(rgb) {
  const matches = REGEX_RGB.exec(rgb);
  if (matches === null)
    return null;
  const components = matches.slice(1).map((v) => v.trim());
  const rgbComponents = rgbComponentStringsToNumber(components);
  if (rgbComponents === null) {
    return null;
  }
  if (void 0 !== rgbComponents.find((v) => isNaN(v) || v < 0 || v > 255)) {
    return null;
  }
  return {
    r: rgbComponents[0],
    g: rgbComponents[1],
    b: rgbComponents[2]
  };
}
function rgbComponentStringsToNumber(components) {
  if (components[0].endsWith("%")) {
    if (void 0 !== components.slice(1, 3).find((c) => !c.endsWith("%"))) {
      return null;
    }
    return components.map((v) => parseFloat(v.substring(0, v.length - 1))).map((v) => Math.floor(v * 255 / 100));
  }
  if (void 0 !== components.slice(1, 3).find((c) => c.endsWith("%"))) {
    return null;
  }
  return components.map((v) => parseInt(v, 10));
}

// src/ui/component/callout-preview.ts
var import_obsidian4 = require("obsidian");
var NO_ATTACH = Symbol();
var CalloutPreviewComponent = class extends import_obsidian4.Component {
  constructor(containerEl, options) {
    super();
    const { color, icon, id, title, content } = options;
    const frag = document.createDocumentFragment();
    const calloutEl = this.calloutEl = frag.createDiv({ cls: ["callout", "calloutmanager-preview"] });
    const titleElContainer = calloutEl.createDiv({ cls: "callout-title" });
    this.iconEl = titleElContainer.createDiv({ cls: "callout-icon" });
    const titleEl = this.titleEl = titleElContainer.createDiv({ cls: "callout-title-inner" });
    const contentEl = this.contentEl = content === void 0 ? void 0 : calloutEl.createDiv({ cls: "callout-content" });
    this.setIcon(icon);
    this.setColor(color);
    this.setCalloutID(id);
    if (title == null)
      titleEl.textContent = id;
    else if (typeof title === "function")
      title(titleEl);
    else if (typeof title === "string")
      titleEl.textContent = title;
    else
      titleEl.appendChild(title);
    if (contentEl != null) {
      if (typeof content === "function")
        content(contentEl);
      else if (typeof content === "string")
        contentEl.textContent = content;
      else
        contentEl.appendChild(content);
    }
    if (containerEl != NO_ATTACH) {
      CalloutPreviewComponent.prototype.attachTo.call(this, containerEl);
    }
  }
  /**
   * Changes the callout ID.
   * This will *not* change the appearance of the preview.
   *
   * @param id The new ID to use.
   */
  setCalloutID(id) {
    const { calloutEl } = this;
    calloutEl.setAttribute("data-callout", id);
    return this;
  }
  /**
   * Changes the callout icon.
   *
   * @param icon The ID of the new icon to use.
   */
  setIcon(icon) {
    const { iconEl, calloutEl } = this;
    calloutEl.style.setProperty("--callout-icon", icon);
    iconEl.empty();
    const iconSvg = (0, import_obsidian4.getIcon)(icon);
    if (iconSvg != null) {
      this.iconEl.appendChild(iconSvg);
    }
    return this;
  }
  /**
   * Changes the callout color.
   *
   * @param color The color to use.
   */
  setColor(color) {
    const { calloutEl } = this;
    if (color == null) {
      calloutEl.style.removeProperty("--callout-color");
      return this;
    }
    calloutEl.style.setProperty("--callout-color", `${color.r}, ${color.g}, ${color.b}`);
    return this;
  }
  /**
   * Attaches the callout preview to a DOM element.
   * This places it at the end of the element.
   *
   * @param containerEl The container to attach to.
   */
  attachTo(containerEl) {
    containerEl.appendChild(this.calloutEl);
    return this;
  }
  /**
   * Resets the `--callout-color` and `--callout-icon` CSS properties added to the callout element.
   */
  resetStylePropertyOverrides() {
    const { calloutEl } = this;
    calloutEl.style.removeProperty("--callout-color");
    calloutEl.style.removeProperty("--callout-icon");
  }
};
var IsolatedCalloutPreviewComponent = class extends CalloutPreviewComponent {
  constructor(containerEl, options) {
    var _a, _b, _c;
    super(NO_ATTACH, options);
    const frag = document.createDocumentFragment();
    const focused = (_a = options.focused) != null ? _a : false;
    const colorScheme = options.colorScheme;
    const readingView = ((_b = options.viewType) != null ? _b : "reading") === "reading";
    const cssEls = (_c = options == null ? void 0 : options.cssEls) != null ? _c : getCurrentStyles(containerEl == null ? void 0 : containerEl.doc);
    const shadowHostEl = this.shadowHostEl = frag.createDiv();
    const shadowRoot = this.shadowRoot = shadowHostEl.attachShadow({ delegatesFocus: false, mode: "closed" });
    const shadowHead = this.shadowHead = shadowRoot.createEl("head");
    const shadowBody = this.shadowBody = shadowRoot.createEl("body");
    const styleEls = this.styleEls = [];
    for (const cssEl of cssEls) {
      const cssElClone = cssEl.cloneNode(true);
      if (cssEl.tagName === "STYLE") {
        styleEls.push(cssElClone);
      }
      shadowHead.appendChild(cssElClone);
    }
    shadowHead.createEl("style", { text: SHADOW_DOM_RESET_STYLES });
    this.customStyleEl = shadowHead.createEl("style", { attr: { "data-custom-styles": "true" } });
    shadowBody.classList.add(`theme-${colorScheme}`, "obsidian-app");
    const viewContentEl = shadowBody.createDiv({ cls: "app-container" }).createDiv({ cls: "horizontal-main-container" }).createDiv({ cls: "workspace" }).createDiv({ cls: "workspace-split mod-root" }).createDiv({ cls: `workspace-tabs ${focused ? "mod-active" : ""}` }).createDiv({ cls: "workspace-tab-container" }).createDiv({ cls: `workspace-leaf ${focused ? "mod-active" : ""}` }).createDiv({ cls: "workspace-leaf-content" }).createDiv({ cls: "view-content" });
    const calloutParentEl = readingView ? createReadingViewContainer(viewContentEl) : createLiveViewContainer(viewContentEl);
    calloutParentEl.appendChild(this.calloutEl);
    if (containerEl != null) {
      IsolatedCalloutPreviewComponent.prototype.attachTo.call(this, containerEl);
    }
  }
  /**
   * Replaces the `<style>` elements used by the isolated callout preview with the latest ones.
   */
  updateStyles() {
    return this.updateStylesWith(
      getCurrentStyles(this.shadowHostEl.doc).filter((e) => e.tagName === "STYLE").map((e) => e.cloneNode(true))
    );
  }
  /**
   * Replaces the `<style>` elements used by the isolated callout preview.
   * This can be used to update the preview with the latest styles.
   *
   * @param styleEls The new style elements to use. These will *not* be cloned.
   */
  updateStylesWith(styleEls) {
    const { styleEls: oldStyleEls, customStyleEl } = this;
    let i, end;
    let lastNode = customStyleEl.previousSibling;
    for (i = 0, end = Math.min(styleEls.length, oldStyleEls.length); i < end; i++) {
      const el = styleEls[i];
      oldStyleEls[i].replaceWith(el);
      lastNode = el;
    }
    for (end = styleEls.length; i < end; i++) {
      const el = styleEls[i];
      lastNode.insertAdjacentElement("afterend", el);
      oldStyleEls.push(el);
    }
    const toRemove = oldStyleEls.splice(i, oldStyleEls.length - i);
    for (const node of toRemove) {
      node.remove();
    }
    return this;
  }
  /**
   * Removes matching style elements.
   * @param predicate The predicate function. If it returns true, the element is removed.
   */
  removeStyles(predicate) {
    for (let i = 0; i < this.styleEls.length; i++) {
      const el = this.styleEls[i];
      if (predicate(el)) {
        el.remove();
        this.styleEls.splice(i, 1);
        i--;
      }
    }
  }
  /**
   * Changes the color scheme.
   * @param colorScheme The color scheme to use.
   */
  setColorScheme(colorScheme) {
    const { classList } = this.shadowBody;
    classList.toggle("theme-dark", colorScheme === "dark");
    classList.toggle("theme-light", colorScheme === "light");
    return this;
  }
  /**
   * Attaches the callout preview to a DOM element.
   * This places it at the end of the element.
   *
   * @param containerEl The container to attach to.
   * @override
   */
  attachTo(containerEl) {
    containerEl.appendChild(this.shadowHostEl);
    return this;
  }
};
function getCurrentStyles(doc) {
  var _a;
  const els = [];
  let node = (doc != null ? doc : window.document).head.firstElementChild;
  for (; node != null; node = node.nextElementSibling) {
    const nodeTag = node.tagName;
    if (nodeTag === "STYLE" || nodeTag === "LINK" && ((_a = node.getAttribute("rel")) == null ? void 0 : _a.toLowerCase()) === "stylesheet") {
      els.push(node);
    }
  }
  return els;
}
function createReadingViewContainer(viewContentEl) {
  return viewContentEl.createDiv({ cls: "markdown-reading-view" }).createDiv({ cls: "markdown-preview-view markdown-rendered" }).createDiv({ cls: "markdown-preview-section" }).createDiv();
}
function createLiveViewContainer(viewContentEl) {
  return viewContentEl.createDiv({ cls: "markdown-source-view cm-s-obsidian mod-cm6 is-live-preview" }).createDiv({ cls: "cm-editor \u037C1 \u037C2 \u037Cq" }).createDiv({ cls: "cm-scroller" }).createDiv({ cls: "cm-sizer" }).createDiv({ cls: "cm-contentContainer" }).createDiv({ cls: "cm-content" }).createDiv({ cls: "cm-embed-block markdown-rendered cm-callout" });
}
var SHADOW_DOM_RESET_STYLES = `
/* Reset layout and stylings for all properties up to the callout. */
.app-container,
.horizontal-main-container,
.workspace,
.workspace-split,
.workspace-tabs,
.workspace-tab-container,
.workspace-leaf,
.workspace-leaf-content,
.view-content,
.markdown-reading-view,
.markdown-source-view,
.cm-editor.\u037C1.\u037C2.\u037Cq,
.cm-editor.\u037C1.\u037C2.\u037Cq > .cm-scroller,
.cm-sizer,
.cm-contentContainer,
.cm-content,
.markdown-preview-view {
	all: initial !important;
	display: block !important;
}

/* Set the text color of the container for the callout. */
.markdown-preview-section,
.cm-callout {
	color: var(--text-normal) !important;
}

/* Override margin on callout to keep the preview as small as possible. */
.markdown-preview-section > div > .callout,
.cm-callout > .callout,
.calloutmanager-preview.callout {
	margin: 0 !important;
}

/* Set the font properties of the callout. */
.cm-callout,
.callout {
	font-size: var(--font-text-size) !important;
	font-family: var(--font-text) !important;
	line-height: var(--line-height-normal) !important;
}

/* Use transparent background color. */
body {
	background-color: transparent !important;
}
`;

// src/callout-resolver.ts
var CalloutResolver = class {
  constructor() {
    this.hostElement = document.body.createDiv({
      cls: "calloutmanager-callout-resolver"
    });
    this.hostElement.style.setProperty("display", "none", "important");
    this.calloutPreview = new IsolatedCalloutPreviewComponent(this.hostElement, {
      id: "",
      icon: "",
      colorScheme: "dark"
    });
    this.calloutPreview.resetStylePropertyOverrides();
  }
  /**
   * Reloads the styles of the callout resolver.
   * This is necessary to get up-to-date styles when the application CSS changes.
   *
   * Note: This will not reload the Obsidian app.css stylesheet.
   * @param styles The new style elements to use.
   */
  reloadStyles() {
    this.calloutPreview.setColorScheme(getCurrentThemeID2(app));
    this.calloutPreview.updateStyles();
    this.calloutPreview.removeStyles((el) => el.getAttribute("data-callout-manager") === "style-overrides");
  }
  /**
   * Removes the host element.
   * This should be called when the plugin is unloading.
   */
  unload() {
    this.hostElement.remove();
  }
  /**
   * Gets the computed styles for a given type of callout.
   * This uses the current Obsidian styles, themes, and snippets.
   *
   * @param id The callout ID.
   * @param callback A callback function to run. The styles may only be accessed through this.
   * @returns Whatever the callback function returned.
   */
  getCalloutStyles(id, callback) {
    const { calloutEl } = this.calloutPreview;
    calloutEl.setAttribute("data-callout", id);
    return callback(window.getComputedStyle(calloutEl));
  }
  /**
   * Gets the icon and color for a given type of callout.
   * This uses the current Obsidian styles, themes, and snippets.
   *
   * @param id The callout ID.
   * @returns The callout icon and color.
   */
  getCalloutProperties(id) {
    return this.getCalloutStyles(id, (styles) => ({
      icon: styles.getPropertyValue("--callout-icon").trim(),
      color: styles.getPropertyValue("--callout-color").trim()
    }));
  }
  get customStyleEl() {
    return this.calloutPreview.customStyleEl;
  }
};
function getColorFromCallout(callout) {
  return parseColorRGB(`rgb(${callout.color})`);
}

// src/api-v1.ts
var _emitter;
var CalloutManagerAPI_V1 = class {
  constructor(plugin, consumer) {
    __privateAdd(this, _emitter, void 0);
    this.plugin = plugin;
    this.consumer = consumer;
    __privateSet(this, _emitter, new import_obsidian5.Events());
    if (consumer != null) {
      console.debug("Created API V1 Handle:", { plugin: consumer.manifest.id });
    }
  }
  /**
   * Called to destroy an API handle bound to a consumer.
   */
  destroy() {
    const consumer = this.consumer;
    console.debug("Destroyed API V1 Handle:", { plugin: consumer.manifest.id });
  }
  /** @override */
  getCallouts() {
    return this.plugin.callouts.values().map((callout) => Object.freeze({ ...callout }));
  }
  /** @override */
  getColor(callout) {
    const color = getColorFromCallout(callout);
    return color != null ? color : { invalid: callout.color };
  }
  /** @override */
  on(event, listener) {
    if (this.consumer == null) {
      throw new Error("Cannot listen for events without an API consumer.");
    }
    __privateGet(this, _emitter).on(event, listener);
  }
  /** @override */
  off(event, listener) {
    if (this.consumer == null) {
      throw new Error("Cannot listen for events without an API consumer.");
    }
    __privateGet(this, _emitter).off(event, listener);
  }
  _emit(event, ...params) {
    __privateGet(this, _emitter).trigger(event, params);
  }
};
_emitter = new WeakMap();

// src/callout-collection.ts
var CalloutCollection = class {
  constructor(resolver) {
    this.resolver = resolver;
    this.invalidated = /* @__PURE__ */ new Set();
    this.invalidationCount = 0;
    this.cacheById = /* @__PURE__ */ new Map();
    this.cached = false;
    this.snippets = new CalloutCollectionSnippets(this.invalidateSource.bind(this));
    this.builtin = new CalloutCollectionObsidian(this.invalidateSource.bind(this));
    this.theme = new CalloutCollectionTheme(this.invalidateSource.bind(this));
    this.custom = new CalloutCollectionCustom(this.invalidateSource.bind(this));
  }
  get(id) {
    if (!this.cached)
      this.buildCache();
    const cached = this.cacheById.get(id);
    if (cached === void 0) {
      return void 0;
    }
    if (this.invalidated.has(cached)) {
      this.resolveOne(cached);
    }
    return cached.callout;
  }
  /**
   * Gets all the known {@link CalloutID callout IDs}.
   * @returns The callout IDs.
   */
  keys() {
    if (!this.cached)
      this.buildCache();
    return Array.from(this.cacheById.keys());
  }
  /**
   * Gets all the known {@link Callout callouts}.
   * @returns The callouts.
   */
  values() {
    if (!this.cached)
      this.buildCache();
    this.resolveAll();
    return Array.from(this.cacheById.values()).map((c) => c.callout);
  }
  /**
   * Returns a function that will return `true` if the collection has changed since the function was created.
   * @returns The function.
   */
  hasChanged() {
    const countSnapshot = this.invalidationCount;
    return () => this.invalidationCount !== countSnapshot;
  }
  /**
   * Resolves the settings of a callout.
   * This removes it from the set of invalidated callout caches.
   *
   * @param cached The callout's cache entry.
   */
  resolveOne(cached) {
    this.doResolve(cached);
    this.invalidated.delete(cached);
  }
  /**
   * Resolves the settings of all callouts.
   */
  resolveAll() {
    for (const cached of this.invalidated.values()) {
      this.doResolve(cached);
    }
    this.invalidated.clear();
  }
  doResolve(cached) {
    cached.callout = this.resolver(cached.id);
    cached.callout.sources = Array.from(cached.sources.values()).map(sourceFromKey);
  }
  /**
   * Builds the initial cache of callouts.
   * This creates the cache entries and associates them to a source.
   */
  buildCache() {
    this.invalidated.clear();
    this.cacheById.clear();
    {
      const source = sourceToKey({ type: "builtin" });
      for (const callout of this.builtin.get()) {
        this.addCalloutSource(callout, source);
      }
    }
    if (this.theme.theme != null) {
      const source = sourceToKey({ type: "theme", theme: this.theme.theme });
      for (const callout of this.theme.get()) {
        this.addCalloutSource(callout, source);
      }
    }
    for (const snippet of this.snippets.keys()) {
      const source = sourceToKey({ type: "snippet", snippet });
      for (const callout of this.snippets.get(snippet)) {
        this.addCalloutSource(callout, source);
      }
    }
    {
      const source = sourceToKey({ type: "custom" });
      for (const callout of this.custom.keys()) {
        this.addCalloutSource(callout, source);
      }
    }
    this.cached = true;
  }
  /**
   * Marks a callout as invalidated.
   * This forces the callout to be resolved again.
   *
   * @param id The callout ID.
   */
  invalidate(id) {
    if (!this.cached)
      return;
    const callout = this.cacheById.get(id);
    if (callout !== void 0) {
      console.debug("Invalided Callout Cache:", id);
      this.invalidated.add(callout);
    }
  }
  addCalloutSource(id, sourceKey) {
    let callout = this.cacheById.get(id);
    if (callout == null) {
      callout = new CachedCallout(id);
      this.cacheById.set(id, callout);
    }
    callout.sources.add(sourceKey);
    this.invalidated.add(callout);
  }
  removeCalloutSource(id, sourceKey) {
    const callout = this.cacheById.get(id);
    if (callout == null) {
      return;
    }
    callout.sources.delete(sourceKey);
    if (callout.sources.size === 0) {
      this.cacheById.delete(id);
      this.invalidated.delete(callout);
    }
  }
  /**
   * Called whenever a callout source has any changes.
   * This will add or remove callouts from the cache, or invalidate a callout to mark it as requiring re-resolving.
   *
   * @param src The source that changed.
   * @param data A diff of changes.
   */
  invalidateSource(src, data) {
    const sourceKey = sourceToKey(src);
    if (!this.cached) {
      return;
    }
    for (const removed of data.removed) {
      this.removeCalloutSource(removed, sourceKey);
    }
    for (const added of data.added) {
      this.addCalloutSource(added, sourceKey);
    }
    for (const changed of data.changed) {
      const callout = this.cacheById.get(changed);
      if (callout != null) {
        this.invalidated.add(callout);
      }
    }
    this.invalidationCount++;
  }
};
var CachedCallout = class {
  constructor(id) {
    this.id = id;
    this.sources = /* @__PURE__ */ new Set();
    this.callout = null;
  }
};
var CalloutCollectionSnippets = class {
  constructor(invalidate) {
    this.data = /* @__PURE__ */ new Map();
    this.invalidate = invalidate;
  }
  get(id) {
    const value = this.data.get(id);
    if (value === void 0) {
      return void 0;
    }
    return Array.from(value.values());
  }
  set(id, callouts) {
    const source = { type: "snippet", snippet: id };
    const old = this.data.get(id);
    const updated = new Set(callouts);
    this.data.set(id, updated);
    if (old === void 0) {
      this.invalidate(source, { added: callouts, changed: [], removed: [] });
      return;
    }
    const diffs = diff(old, updated);
    this.invalidate(source, {
      added: diffs.added,
      removed: diffs.removed,
      changed: diffs.same
    });
  }
  delete(id) {
    const old = this.data.get(id);
    const deleted = this.data.delete(id);
    if (old !== void 0) {
      this.invalidate(
        { type: "snippet", snippet: id },
        {
          added: [],
          changed: [],
          removed: Array.from(old.keys())
        }
      );
    }
    return deleted;
  }
  clear() {
    for (const id of Array.from(this.data.keys())) {
      this.delete(id);
    }
  }
  keys() {
    return Array.from(this.data.keys());
  }
};
var CalloutCollectionObsidian = class {
  constructor(invalidate) {
    this.data = /* @__PURE__ */ new Set();
    this.invalidate = invalidate;
  }
  set(callouts) {
    const old = this.data;
    const updated = this.data = new Set(callouts);
    const diffs = diff(old, updated);
    this.invalidate(
      { type: "builtin" },
      {
        added: diffs.added,
        removed: diffs.removed,
        changed: diffs.same
      }
    );
  }
  get() {
    return Array.from(this.data.values());
  }
};
var CalloutCollectionTheme = class {
  constructor(invalidate) {
    this.data = /* @__PURE__ */ new Set();
    this.invalidate = invalidate;
    this.oldTheme = "";
  }
  get theme() {
    return this.oldTheme;
  }
  set(theme, callouts) {
    const old = this.data;
    const oldTheme = this.oldTheme;
    const updated = this.data = new Set(callouts);
    this.oldTheme = theme;
    if (this.oldTheme === theme) {
      const diffs = diff(old, updated);
      this.invalidate(
        { type: "theme", theme },
        {
          added: diffs.added,
          removed: diffs.removed,
          changed: diffs.same
        }
      );
      return;
    }
    this.invalidate(
      { type: "theme", theme: oldTheme != null ? oldTheme : "" },
      {
        added: [],
        removed: Array.from(old.values()),
        changed: []
      }
    );
    this.invalidate(
      { type: "theme", theme },
      {
        added: callouts,
        removed: [],
        changed: []
      }
    );
  }
  delete() {
    const old = this.data;
    const oldTheme = this.oldTheme;
    this.data = /* @__PURE__ */ new Set();
    this.oldTheme = null;
    this.invalidate(
      { type: "theme", theme: oldTheme != null ? oldTheme : "" },
      {
        added: [],
        removed: Array.from(old.values()),
        changed: []
      }
    );
  }
  get() {
    return Array.from(this.data.values());
  }
};
var CalloutCollectionCustom = class {
  constructor(invalidate) {
    this.data = [];
    this.invalidate = invalidate;
  }
  has(id) {
    return void 0 !== this.data.find((existingId) => existingId === id);
  }
  add(...ids) {
    const set = new Set(this.data);
    const added = [];
    for (const id of ids) {
      if (!set.has(id)) {
        added.push(id);
        set.add(id);
        this.data.push(id);
      }
    }
    if (added.length > 0) {
      this.invalidate({ type: "custom" }, { added, removed: [], changed: [] });
    }
  }
  delete(...ids) {
    const { data } = this;
    const removed = [];
    for (const id of ids) {
      const index = data.findIndex((existingId) => id === existingId);
      if (index !== void 0) {
        data.splice(index, 1);
        removed.push(id);
      }
    }
    if (removed.length > 0) {
      this.invalidate({ type: "custom" }, { added: [], removed, changed: [] });
    }
  }
  keys() {
    return this.data.slice(0);
  }
  clear() {
    const removed = this.data;
    this.data = [];
    this.invalidate({ type: "custom" }, { added: [], removed, changed: [] });
  }
};
function diff(before, after) {
  const added = [];
  const removed = [];
  const same = [];
  for (const item of before.values()) {
    (after.has(item) ? same : removed).push(item);
  }
  for (const item of after.values()) {
    if (!before.has(item)) {
      added.push(item);
    }
  }
  return { added, removed, same };
}
function sourceToKey(source) {
  switch (source.type) {
    case "builtin":
      return "builtin";
    case "snippet":
      return `snippet:${source.snippet}`;
    case "theme":
      return `theme:${source.theme}`;
    case "custom":
      return `custom`;
  }
}
function sourceFromKey(sourceKey) {
  if (sourceKey === "builtin") {
    return { type: "builtin" };
  }
  if (sourceKey === "custom") {
    return { type: "custom" };
  }
  if (sourceKey.startsWith("snippet:")) {
    return { type: "snippet", snippet: sourceKey.substring("snippet:".length) };
  }
  if (sourceKey.startsWith("theme:")) {
    return { type: "theme", theme: sourceKey.substring("theme:".length) };
  }
  throw new Error("Unknown source key: " + sourceKey);
}

// src/callout-fallback-obsidian.json
var callout_fallback_obsidian_default = [
  "quote",
  "cite",
  "warning",
  "caution",
  "attention",
  "help",
  "faq",
  "success",
  "check",
  "done",
  "abstract",
  "summary",
  "tldr",
  "important",
  "tip",
  "hint",
  "info",
  "todo",
  "example",
  "failure",
  "fail",
  "missing",
  "danger",
  "error",
  "bug"
];

// src/callout-settings.ts
function currentCalloutEnvironment(app2) {
  var _a;
  const theme = (_a = getCurrentThemeID(app2)) != null ? _a : "<default>";
  return {
    theme,
    colorScheme: getCurrentThemeID2(app2)
  };
}
function calloutSettingsToCSS(id, settings, environment) {
  const styles = calloutSettingsToStyles(settings, environment).join(";\n	");
  if (styles.length === 0) {
    return "";
  }
  return `.callout[data-callout="${id}"] {
	` + styles + "\n}";
}
function calloutSettingsToStyles(settings, environment) {
  const styles = [];
  for (const setting of settings) {
    if (!checkCondition(setting.condition, environment)) {
      continue;
    }
    const { changes } = setting;
    if (changes.color != null)
      styles.push(`--callout-color: ${changes.color}`);
    if (changes.icon != null)
      styles.push(`--callout-icon: ${changes.icon}`);
    if (changes.customStyles != null)
      styles.push(changes.customStyles);
  }
  return styles;
}
function checkCondition(condition, environment) {
  if (condition == null) {
    return true;
  }
  if ("or" in condition && condition.or !== void 0) {
    return condition.or.findIndex((p) => checkCondition(p, environment) === true) !== void 0;
  }
  if ("and" in condition && condition.and !== void 0) {
    return condition.and.findIndex((p) => checkCondition(p, environment) === false) === void 0;
  }
  if ("theme" in condition && condition.theme === environment.theme) {
    return true;
  }
  if ("colorScheme" in condition && condition.colorScheme === environment.colorScheme) {
    return true;
  }
  return false;
}
function typeofCondition(condition) {
  if (condition === void 0)
    return void 0;
  const hasOwnProperty = Object.prototype.hasOwnProperty.bind(condition);
  if (hasOwnProperty("colorScheme"))
    return "colorScheme";
  if (hasOwnProperty("theme"))
    return "theme";
  if (hasOwnProperty("and"))
    return "and";
  if (hasOwnProperty("or"))
    return "or";
  throw new Error(`Unsupported condition: ${JSON.stringify(condition)}`);
}

// src/css-parser.ts
function getCalloutsFromCSS(css) {
  var _a;
  const REGEX_CALLOUT_SELECTOR = /\[data-callout([^\]]*)\]/gmi;
  const REGEX_MATCH_QUOTED_STRING = {
    "'": /^'([^']+)'( i)?$/,
    '"': /^"([^"]+)"( i)?$/,
    "": /^([^\]]+)$/
  };
  const attributeSelectors = [];
  let matches;
  while ((matches = REGEX_CALLOUT_SELECTOR.exec(css)) != null) {
    attributeSelectors.push(matches[1]);
    REGEX_CALLOUT_SELECTOR.lastIndex = matches.index + matches[0].length;
  }
  const ids = [];
  for (const attributeSelector of attributeSelectors) {
    let selectorString;
    if (attributeSelector.startsWith("=")) {
      selectorString = attributeSelector.substring(1);
    } else if (attributeSelector.startsWith("^=")) {
      selectorString = attributeSelector.substring(2);
    } else {
      continue;
    }
    const quoteChar = selectorString.charAt(0);
    const stringRegex = (_a = REGEX_MATCH_QUOTED_STRING[quoteChar]) != null ? _a : REGEX_MATCH_QUOTED_STRING[""];
    const matches2 = stringRegex.exec(selectorString);
    if (matches2 != null && matches2[1] != null) {
      ids.push(matches2[1]);
    }
  }
  return ids;
}

// src/css-watcher.ts
var StylesheetWatcher = class {
  constructor(app2, disableObsidianStylesheet) {
    this.app = app2;
    this.listeners = /* @__PURE__ */ new Map();
    this.cachedSnippets = /* @__PURE__ */ new Map();
    this.cachedObsidian = disableObsidianStylesheet ? false : null;
    this.cachedTheme = null;
    this.watching = false;
    this.disableObsidianStylesheet = disableObsidianStylesheet;
  }
  /**
   * Start watching for changes to stylesheets.
   * @returns A callback function to pass to {@link Plugin.register}.
   */
  watch() {
    if (this.watching) {
      throw new Error("Already watching.");
    }
    const events = [
      {
        event: "css-change",
        listener: () => this.checkForChanges(false),
        target: this.app.workspace
      }
    ];
    for (const evtl of events) {
      evtl.target.on(evtl.event, evtl.listener);
    }
    this.checkForChanges();
    return () => {
      if (!this.watching) {
        return;
      }
      for (const evtl of events) {
        evtl.target.off(evtl.event, evtl.listener);
      }
      this.watching = false;
    };
  }
  /**
   * @internal
   */
  on(event, listener) {
    let listenersForEvent = this.listeners.get(event);
    if (listenersForEvent === void 0) {
      listenersForEvent = /* @__PURE__ */ new Set();
      this.listeners.set(event, listenersForEvent);
    }
    listenersForEvent.add(listener);
  }
  /**
   * Removes an event listener.
   *
   * @param event The event.
   * @param listener The listener to remove.
   */
  off(event, listener) {
    const listenersForEvent = this.listeners.get(event);
    if (listenersForEvent === void 0) {
      return;
    }
    listenersForEvent.delete(listener);
    if (listenersForEvent.size === 0) {
      this.listeners.delete(event);
    }
  }
  emit(event, ...data) {
    const listenersForEvent = this.listeners.get(event);
    if (listenersForEvent === void 0) {
      return;
    }
    for (const listener of listenersForEvent) {
      listener(...data);
    }
  }
  /**
   * Checks for any changes to the application stylesheets.
   * If {@link watch} is being used, this will be called automatically.
   *
   * @param clear If set to true, the cache will be cleared.
   * @returns True if there were any changes.
   */
  async checkForChanges(clear) {
    let changed = false;
    this.emit("checkStarted");
    if (clear === true) {
      this.cachedSnippets.clear();
      this.cachedTheme = null;
      this.cachedObsidian = null;
    }
    if (this.cachedObsidian == null && !this.disableObsidianStylesheet) {
      changed = await this.checkForChangesObsidian() || changed;
    }
    changed = this.checkForChangesSnippets() || changed;
    changed = this.checkForChangesTheme() || changed;
    this.emit("checkComplete", changed);
    return changed;
  }
  /**
   * Attempts to fetch the Obsidian built-in stylesheet.
   * This will fail if the version of obsidian is newer than the version supported by `obsidian-extra`.
   *
   * @returns true if the fetch was successful.
   */
  async checkForChangesObsidian() {
    if (this.cachedObsidian === false) {
      return false;
    }
    try {
      this.cachedObsidian = await fetchObsidianStyles(this.app);
      this.emit("change", {
        type: "obsidian",
        styles: this.cachedObsidian
      });
      return true;
    } catch (ex) {
      this.cachedObsidian = false;
      console.warn("Unable to fetch Obsidian stylesheet.", ex);
      return false;
    }
  }
  /**
   * Checks for changes in the application's theme.
   */
  checkForChangesTheme() {
    var _a;
    const theme = getCurrentThemeID(this.app);
    const themeManifest = theme == null ? null : getThemeManifest(this.app, theme);
    const hasTheme = theme != null && themeManifest != null;
    const styleEl = getThemeStyleElement(this.app);
    const styles = (_a = styleEl == null ? void 0 : styleEl.textContent) != null ? _a : "";
    if (this.cachedTheme != null && !hasTheme) {
      this.emit("remove", { type: "theme", theme: this.cachedTheme.id, styles: this.cachedTheme.contents });
      this.cachedTheme = null;
      return true;
    }
    if (this.cachedTheme == null && hasTheme) {
      this.cachedTheme = { id: theme, version: themeManifest.version, contents: styles };
      this.emit("add", { type: "theme", theme, styles });
      return true;
    }
    if (!hasTheme || this.cachedTheme == null) {
      return false;
    }
    const changed = this.cachedTheme.id !== theme || // Active theme changed
    this.cachedTheme.version !== themeManifest.version || // Version of active theme changed
    this.cachedTheme.contents !== styles;
    if (changed) {
      this.cachedTheme = {
        id: theme,
        version: themeManifest.version,
        contents: styles
      };
      this.emit("change", { type: "theme", theme, styles });
    }
    return changed;
  }
  /**
   * Checks for changes in the enabled snippets.
   */
  checkForChangesSnippets() {
    let anyChanges = false;
    const snippets = getSnippetStyleElements(this.app);
    const knownSnippets = Array.from(this.cachedSnippets.entries());
    for (const [id, cachedStyles] of knownSnippets) {
      const styleEl = snippets.get(id);
      if (styleEl == null) {
        this.cachedSnippets.delete(id);
        this.emit("remove", { type: "snippet", snippet: id, styles: cachedStyles });
        anyChanges = true;
        continue;
      }
      if (styleEl.textContent != null && styleEl.textContent !== cachedStyles) {
        this.cachedSnippets.set(id, styleEl.textContent);
        this.emit("change", { type: "snippet", snippet: id, styles: styleEl.textContent });
        anyChanges = true;
      }
    }
    for (const [id, styleEl] of snippets.entries()) {
      if (styleEl == null)
        continue;
      if (!this.cachedSnippets.has(id) && styleEl.textContent != null) {
        this.cachedSnippets.set(id, styleEl.textContent);
        this.emit("add", { type: "snippet", snippet: id, styles: styleEl.textContent });
        anyChanges = true;
      }
    }
    return anyChanges;
  }
  /**
   * Returns true if fetching the Obsidian stylesheet is supported.
   */
  isObsidianStylesheetSupported() {
    return !this.disableObsidianStylesheet && this.cachedObsidian !== false;
  }
};

// src/panes/manage-callouts-pane.ts
var import_obsidian16 = require("obsidian");

// src/ui/pane.ts
var UIPane = class {
  /**
   * Called to display the controls for the pane.
   */
  displayControls() {
  }
  /**
   * Called when the pane is created and attached to the setting tab, but before {@link display} is called.
   */
  onReady() {
  }
  /**
   * Called when the pane is removed and ready to be destroyed.
   * Any important settings should be saved here.
   *
   * @param cancelled If true, the user closed the pane with the escape key.
   */
  onClose(cancelled) {
  }
  /**
   * Called to save the state of the setting pane.
   * This is used for suspending a pane when another pane covers it up.
   *
   * @returns The saved state.
   */
  suspendState() {
    return void 0;
  }
  /**
   * Called to load the state of the setting pane.
   * This is called before {@link display}.
   *
   * @param state The state to restore.
   */
  restoreState(state) {
  }
};

// src/panes/create-callout-pane.ts
var import_obsidian15 = require("obsidian");

// src/panes/edit-callout-pane/index.ts
var import_obsidian14 = require("obsidian");

// src/panes/edit-callout-pane/appearance-type.ts
function determineAppearanceType(settings) {
  var _a;
  return (_a = determineNonComplexAppearanceType(settings)) != null ? _a : {
    type: "complex",
    settings
  };
}
function determineNonComplexAppearanceType(settings) {
  var _a, _b;
  const settingsWithColorSchemeCondition = [];
  const settingsWithNoCondition = [];
  for (const setting of settings) {
    const type = typeofCondition(setting.condition);
    switch (type) {
      case "colorScheme":
        settingsWithColorSchemeCondition.push(setting);
        break;
      case void 0:
        settingsWithNoCondition.push(setting);
        break;
      case "and":
      case "or":
      case "theme": {
        console.debug("Cannot represent callout settings with UI.", {
          reason: `Has condition of type '${type}'`,
          settings
        });
        return null;
      }
    }
  }
  const colorSchemeColor = { dark: void 0, light: void 0 };
  for (const setting of settingsWithColorSchemeCondition) {
    const changed = Object.keys(setting.changes);
    if (changed.length === 0) {
      continue;
    }
    if (changed.find((key) => key !== "color") !== void 0) {
      console.debug("Cannot represent callout settings with UI.", {
        reason: `Has 'colorScheme' condition with non-color change.`,
        settings
      });
      return null;
    }
    const appearanceCond = setting.condition.colorScheme;
    if (colorSchemeColor[appearanceCond] !== void 0) {
      console.debug("Cannot represent callout settings with UI.", {
        reason: `Has multiple 'colorScheme' conditions that change ${appearanceCond} color.`,
        settings
      });
      return null;
    }
    colorSchemeColor[appearanceCond] = setting.changes.color;
  }
  const otherChanges = {};
  for (const [change, value] of settingsWithNoCondition.flatMap((s) => Object.entries(s.changes))) {
    if (value === void 0)
      continue;
    if (change in otherChanges) {
      console.debug("Cannot represent callout settings with UI.", {
        reason: `Has multiple changes to '${change}'.`,
        settings
      });
      return null;
    }
    otherChanges[change] = value;
  }
  const otherChangesColor = otherChanges.color;
  delete otherChanges.color;
  if (colorSchemeColor.dark === void 0 && colorSchemeColor.light === void 0) {
    if (otherChangesColor === void 0) {
      return { type: "unified", color: void 0, otherChanges };
    }
    return { type: "unified", color: otherChangesColor, otherChanges };
  }
  const colorDark = (_a = colorSchemeColor.dark) != null ? _a : colorSchemeColor.light;
  const colorLight = (_b = colorSchemeColor.light) != null ? _b : colorSchemeColor.dark;
  return { type: "per-scheme", colorDark, colorLight, otherChanges };
}

// src/panes/edit-callout-pane/editor-complex.ts
var import_obsidian6 = require("obsidian");

// src/panes/edit-callout-pane/appearance-editor.ts
var AppearanceEditor = class {
};

// src/panes/edit-callout-pane/editor-complex.ts
var ComplexAppearanceEditor = class extends AppearanceEditor {
  /** @override */
  toSettings() {
    return this.appearance.settings;
  }
  /** @override */
  render() {
    const { containerEl } = this;
    const { settings } = this.appearance;
    const complexJson = JSON.stringify(settings, void 0, "  ");
    containerEl.createEl("p", {
      text: "This callout has been configured using the plugin's data.json file. To prevent unintentional changes to the configuration, you need to edit it manually."
    });
    containerEl.createEl("code", { cls: "calloutmanager-edit-callout-appearance-json" }, (el) => {
      el.createEl("pre", { text: complexJson });
    });
    containerEl.createEl("p", {
      text: "Alternatively, you can reset the callout by clicking the button below twice."
    });
    let resetButtonClicked = false;
    const resetButton = new import_obsidian6.ButtonComponent(containerEl).setButtonText("Reset Callout").setClass("calloutmanager-edit-callout-appearance-reset").setWarning().onClick(() => {
      if (!resetButtonClicked) {
        resetButtonClicked = true;
        resetButton.setButtonText("Are you sure?");
        return;
      }
      this.setAppearance({ type: "unified", color: void 0, otherChanges: {} });
    });
  }
};

// src/ui/setting/callout-color.ts
var import_obsidian8 = require("obsidian");

// src/ui/component/reset-button.ts
var import_obsidian7 = require("obsidian");
var ResetButtonComponent = class extends import_obsidian7.ExtraButtonComponent {
  constructor(containerEl) {
    super(containerEl);
    this.setIcon("lucide-undo");
    this.extraSettingsEl.classList.add("calloutmanager-reset-button");
  }
};

// src/ui/setting/callout-color.ts
var CalloutColorSetting = class extends import_obsidian8.Setting {
  constructor(containerEl, callout) {
    super(containerEl);
    this.onChanged = void 0;
    this.callout = callout;
    this.isDefault = true;
    this.addColorPicker((picker) => {
      this.colorComponent = picker;
      picker.onChange(() => {
        var _a;
        const { r, g, b } = this.getColor();
        (_a = this.onChanged) == null ? void 0 : _a.call(this, `${r}, ${g}, ${b}`);
      });
    });
    this.components.push(
      new ResetButtonComponent(this.controlEl).then((btn) => {
        this.resetComponent = btn;
        btn.onClick(() => {
          var _a;
          return (_a = this.onChanged) == null ? void 0 : _a.call(this, void 0);
        });
      })
    );
    this.setColor(void 0);
  }
  /**
   * Sets the color string.
   * This only accepts comma-delimited RGB values.
   *
   * @param color The color (e.g. `255, 10, 25`) or undefined to reset the color to default.
   * @returns `this`, for chaining.
   */
  setColorString(color) {
    var _a;
    if (color == null) {
      return this.setColor(void 0);
    }
    return this.setColor((_a = parseColorRGB(`rgb(${color})`)) != null ? _a : { r: 0, g: 0, b: 0 });
  }
  /**
   * Sets the color.
   *
   * @param color The color or undefined to reset the color to default.
   * @returns `this`, for chaining.
   */
  setColor(color) {
    var _a;
    const isDefault = this.isDefault = color == null;
    if (color == null) {
      color = (_a = getColorFromCallout(this.callout)) != null ? _a : { r: 0, g: 0, b: 0 };
    }
    if (color instanceof Array) {
      color = { r: color[0], g: color[1], b: color[2] };
    }
    this.colorComponent.setValueRgb(color);
    this.resetComponent.setDisabled(isDefault).setTooltip(isDefault ? "" : "Reset Color");
    return this;
  }
  getColor() {
    return this.colorComponent.getValueRgb();
  }
  isDefaultColor() {
    return this.isDefault;
  }
  onChange(cb) {
    this.onChanged = cb;
    return this;
  }
};

// src/ui/setting/callout-icon.ts
var import_obsidian11 = require("obsidian");

// src/panes/select-icon-pane.ts
var import_obsidian10 = require("obsidian");

// src/ui/component/icon-preview.ts
var import_obsidian9 = require("obsidian");
var IconPreviewComponent = class extends import_obsidian9.Component {
  constructor(containerEl) {
    super();
    this.componentEl = containerEl.createEl("button", { cls: "calloutmanager-icon-preview" });
    this.iconEl = this.componentEl.createDiv({ cls: "calloutmanager-icon-preview--icon" });
    this.idEl = this.componentEl.createDiv({ cls: "calloutmanager-icon-preview--id" });
  }
  /**
   * Sets the icon of the icon preview component.
   * This will update the label and the icon SVG.
   *
   * @param icon The icon name.
   * @returns This, for chaining.
   */
  setIcon(icon) {
    const iconSvg = (0, import_obsidian9.getIcon)(icon);
    this.componentEl.setAttribute("data-icon-id", icon);
    this.idEl.textContent = icon;
    this.iconEl.empty();
    if (iconSvg != null) {
      this.iconEl.appendChild(iconSvg);
    }
    return this;
  }
  /**
   * Sets the `click` event listener for the component.
   *
   * @param listener The listener.
   * @returns This, for chaining.
   */
  onClick(listener) {
    this.componentEl.onclick = listener;
    return this;
  }
};

// src/panes/select-icon-pane.ts
var recentIcons = /* @__PURE__ */ new Set();
var SelectIconPane = class extends UIPane {
  constructor(plugin, title, options) {
    var _a;
    super();
    this.title = title;
    this.plugin = plugin;
    this.onChoose = options.onChoose;
    this.previewLimit = (_a = options.limit) != null ? _a : 250;
    this.previewLimitOverage = 0;
    this.searchQuery = "";
    this.searchResults = [];
    const usedIconIds = new Set(plugin.callouts.values().map((c) => c.icon));
    const usedIcons = this.usedIcons = /* @__PURE__ */ new Map();
    this.allIcons = (0, import_obsidian10.getIconIds)().map((id) => {
      const icon = {
        id,
        searchId: id.trim().toLowerCase(),
        component: null,
        searchResult: null
      };
      if (usedIconIds.has(id)) {
        this.usedIcons.set(id, icon);
      }
      return icon;
    });
    this.compareIcons = ({ id: a, searchId: aLC, searchResult: aSR }, { id: b, searchId: bLC, searchResult: bSR }) => {
      var _a2, _b;
      const recency = (recentIcons.has(b) ? 1 : 0) - (recentIcons.has(a) ? 1 : 0);
      const suggested = (usedIcons.has(b) ? 1 : 0) - (usedIcons.has(a) ? 1 : 0);
      const searchRank = ((_a2 = bSR == null ? void 0 : bSR.score) != null ? _a2 : 0) - ((_b = aSR == null ? void 0 : aSR.score) != null ? _b : 0);
      const sum = recency + suggested + searchRank;
      if (sum !== 0)
        return sum;
      return bLC.localeCompare(aLC);
    };
  }
  /**
   * Changes the search query.
   * @param query The search query.
   */
  search(query) {
    this.searchQuery = query;
    if (query === "") {
      this.resetSearchResults();
    } else {
      const search = (0, import_obsidian10.prepareFuzzySearch)(query.trim().toLowerCase());
      this.calculateSearchResults((icon) => search(icon.searchId));
    }
    this.display();
  }
  /**
   * Updatse the search results list.
   * @param search The search function.
   */
  calculateSearchResults(search) {
    this.searchResults = this.allIcons.filter((icon) => {
      icon.searchResult = search(icon);
      return icon.searchResult != null;
    });
    this.searchResults.sort(this.compareIcons);
    this.previewLimitOverage = this.searchResults.splice(this.previewLimit).length;
  }
  /**
   * Resets the search results list to show a default list of suggested icons.
   */
  resetSearchResults() {
    const { allIcons, previewLimit, usedIcons } = this;
    this.searchResults = Array.from(
      (/* @__PURE__ */ new Set([
        ...allIcons.slice(0, previewLimit),
        ...Array.from(usedIcons.values()).slice(0, previewLimit)
      ])).values()
    );
    this.searchResults.sort(this.compareIcons).slice(0, this.previewLimit);
    this.previewLimitOverage = this.allIcons.length - this.searchResults.length;
  }
  /** @override */
  display() {
    const { containerEl } = this;
    const gridEl = document.createDocumentFragment().createDiv({ cls: "calloutmanager-icon-picker" });
    for (const icon of this.searchResults) {
      if (icon.component == null) {
        icon.component = new IconPreviewComponent(gridEl).setIcon(icon.id).componentEl;
      } else {
        gridEl.appendChild(icon.component);
      }
    }
    gridEl.addEventListener("click", ({ targetNode }) => {
      for (; targetNode != null && targetNode !== gridEl; targetNode = targetNode.parentElement) {
        if (!(targetNode instanceof HTMLElement))
          continue;
        const iconId = targetNode.getAttribute("data-icon-id");
        if (iconId != null) {
          recentIcons.add(iconId);
          this.nav.close();
          this.onChoose(iconId);
          return;
        }
      }
    });
    containerEl.empty();
    containerEl.appendChild(gridEl);
    const { previewLimitOverage } = this;
    if (previewLimitOverage > 0) {
      const { pluralIs, pluralIcon } = previewLimitOverage === 1 ? { pluralIs: "is", pluralIcon: "icon" } : { pluralIs: "are", pluralIcon: "icons" };
      containerEl.createEl("p", {
        text: `There ${pluralIs} ${previewLimitOverage} more ${pluralIcon} to show. Refine your search to see more.`
      });
    }
  }
  /** @override */
  displayControls() {
    const { controlsEl } = this;
    new import_obsidian10.TextComponent(controlsEl).setValue(this.searchQuery).setPlaceholder("Search icons...").onChange(this.search.bind(this));
  }
  /** @override */
  onReady() {
    this.resetSearchResults();
  }
};

// src/ui/setting/callout-icon.ts
var CalloutIconSetting = class extends import_obsidian11.Setting {
  constructor(containerEl, callout, plugin, getNav) {
    super(containerEl);
    this.onChanged = void 0;
    this.callout = callout;
    this.isDefault = true;
    this.iconName = void 0;
    this.addButton((btn) => {
      this.buttonComponent = btn;
      btn.onClick(() => {
        getNav().open(
          new SelectIconPane(plugin, "Select Icon", { onChoose: (icon) => {
            var _a;
            return (_a = this.onChanged) == null ? void 0 : _a.call(this, icon);
          } })
        );
      });
    });
    this.components.push(
      new ResetButtonComponent(this.controlEl).then((btn) => {
        this.resetComponent = btn;
        btn.onClick(() => {
          var _a;
          return (_a = this.onChanged) == null ? void 0 : _a.call(this, void 0);
        });
      })
    );
    this.setIcon(void 0);
  }
  /**
   * Sets the icon.
   *
   * @param icon The icon name or undefined to reset the color to default.
   * @returns `this`, for chaining.
   */
  setIcon(icon) {
    const isDefault = this.isDefault = icon == null;
    const iconName = this.iconName = icon != null ? icon : this.callout.icon;
    const iconExists = (0, import_obsidian11.getIcon)(iconName) != null;
    if (iconExists) {
      this.buttonComponent.setIcon(iconName);
    } else {
      this.buttonComponent.setButtonText(iconExists ? "" : `(missing icon: ${iconName})`);
    }
    this.resetComponent.setDisabled(isDefault).setTooltip(isDefault ? "" : "Reset Icon");
    return this;
  }
  getIcon() {
    var _a;
    return (_a = this.iconName) != null ? _a : this.callout.icon;
  }
  isDefaultIcon() {
    return this.isDefault;
  }
  onChange(cb) {
    this.onChanged = cb;
    return this;
  }
};

// src/panes/edit-callout-pane/editor-per-scheme.ts
var PerSchemeAppearanceEditor = class extends AppearanceEditor {
  /** @override */
  toSettings() {
    const { otherChanges, colorDark, colorLight } = this.appearance;
    const forLight = {
      condition: { colorScheme: "light" },
      changes: {
        color: colorLight
      }
    };
    const forDark = {
      condition: { colorScheme: "dark" },
      changes: {
        color: colorDark
      }
    };
    if (forLight.changes.color === void 0)
      delete forLight.changes.color;
    if (forDark.changes.color === void 0)
      delete forDark.changes.color;
    return [{ changes: otherChanges }, forLight, forDark];
  }
  setAppearanceOrChangeToUnified(appearance) {
    const { colorDark, colorLight, otherChanges } = appearance;
    if (colorDark === void 0 && colorLight === void 0) {
      this.setAppearance({ type: "unified", color: void 0, otherChanges });
      return;
    }
    this.setAppearance(appearance);
  }
  render() {
    const { callout, containerEl, appearance, plugin, nav } = this;
    const { colorDark, colorLight, otherChanges } = this.appearance;
    new CalloutColorSetting(containerEl, callout).setName("Dark Color").setDesc("Change the color of the callout for the dark color scheme.").setColorString(colorDark).onChange((color) => this.setAppearanceOrChangeToUnified({ ...appearance, colorDark: color }));
    new CalloutColorSetting(containerEl, callout).setName(`Light Color`).setDesc(`Change the color of the callout for the light color scheme.`).setColorString(colorLight).onChange((color) => this.setAppearanceOrChangeToUnified({ ...appearance, colorLight: color }));
    new CalloutIconSetting(containerEl, callout, plugin, () => nav).setName("Icon").setDesc("Change the callout icon.").setIcon(otherChanges.icon).onChange(
      (icon) => this.setAppearanceOrChangeToUnified({ ...appearance, otherChanges: { ...otherChanges, icon } })
    );
  }
};

// src/panes/edit-callout-pane/editor-unified.ts
var import_obsidian12 = require("obsidian");
var UnifiedAppearanceEditor = class extends AppearanceEditor {
  /** @override */
  toSettings() {
    const { otherChanges, color } = this.appearance;
    const changes = {
      ...otherChanges,
      color
    };
    if (color === void 0) {
      delete changes.color;
    }
    return [{ changes }];
  }
  render() {
    const { plugin, containerEl, callout, setAppearance } = this;
    const { color, otherChanges } = this.appearance;
    const colorScheme = getCurrentThemeID2(plugin.app);
    const otherColorScheme = colorScheme === "dark" ? "light" : "dark";
    new CalloutColorSetting(containerEl, callout).setName("Color").setDesc("Change the color of the callout.").setColorString(color).onChange((color2) => setAppearance({ type: "unified", otherChanges, color: color2 }));
    new import_obsidian12.Setting(containerEl).setName(`Color Scheme`).setDesc(`Change the color of the callout for the ${otherColorScheme} color scheme.`).addButton(
      (btn) => btn.setClass("clickable-icon").setIcon("lucide-sun-moon").onClick(() => {
        const currentColor = color != null ? color : callout.color;
        setAppearance({
          type: "per-scheme",
          colorDark: currentColor,
          colorLight: currentColor,
          otherChanges
        });
      })
    );
    new CalloutIconSetting(containerEl, callout, plugin, () => this.nav).setName("Icon").setDesc("Change the callout icon.").setIcon(otherChanges.icon).onChange((icon) => setAppearance({ type: "unified", color, otherChanges: { ...otherChanges, icon } }));
  }
};

// src/panes/edit-callout-pane/section-info.ts
function renderInfo(app2, callout, containerEl) {
  const frag = document.createDocumentFragment();
  const contentEl = frag.createDiv({ cls: "calloutmanager-edit-callout-section" });
  contentEl.createEl("h2", { text: "About this Callout" });
  contentEl.createEl("div", { cls: "calloutmanager-edit-callout-info" }, (el) => {
    el.appendText("The ");
    el.createSpan({ cls: "calloutmanager-edit-callout--callout-id", text: callout.id });
    el.appendText(" callout");
    el.appendText(" has ");
    appendColorInfo(el, callout);
    el.appendText(" and ");
    appendIconInfo(el, callout);
    if (callout.sources.length === 1) {
      if (callout.sources[0].type === "builtin") {
        el.appendText(". It is one of the built-in callouts.");
        return;
      }
      el.appendText(". It was added to Obsidian by the ");
      appendSourceInfo(app2, el, callout.sources[0]);
      el.appendText(".");
      return;
    }
    el.appendText(". The callout comes from:");
    const sources = el.createEl("ul", { cls: "calloutmanager-edit-callout--callout-source-list" });
    for (const source of callout.sources) {
      const itemEl = sources.createEl("li");
      itemEl.appendText("The ");
      appendSourceInfo(app2, itemEl, source);
      itemEl.appendText(".");
    }
  });
  containerEl.appendChild(frag);
}
function appendIconInfo(el, callout) {
  el.appendText("is using the icon ");
  el.createEl("code", { cls: "calloutmanager-edit-callout--callout-icon", text: callout.icon });
}
function appendColorInfo(el, callout) {
  const calloutColor = getColorFromCallout(callout);
  if (calloutColor == null) {
    el.appendText("an invalid color (");
    el.createEl("code", {
      cls: "calloutmanager-edit-callout--color-invalid",
      text: callout.color.trim()
    });
    el.appendText(")");
    return;
  }
  el.appendText("the color ");
  el.createEl(
    "code",
    { cls: "calloutmanager-edit-callout--callout-color", text: toHexRGB(calloutColor) },
    (colorEl) => colorEl.style.setProperty("--resolved-callout-color", callout.color)
  );
}
function appendSourceInfo(app2, el, source) {
  var _a, _b;
  switch (source.type) {
    case "builtin":
      el.appendText("built-in callouts");
      return true;
    case "custom":
      el.appendText("custom callouts you created");
      return true;
    case "snippet":
      el.appendText("CSS snippet ");
      el.createEl("code", {
        cls: "calloutmanager-edit-callout--callout-source",
        text: `${source.snippet}.css`
      });
      return true;
    case "theme": {
      el.appendText("theme ");
      const themeName = (_b = (_a = getThemeManifest(app2, source.theme)) == null ? void 0 : _a.name) != null ? _b : source.theme;
      el.createSpan({ cls: "calloutmanager-edit-callout--callout-source", text: themeName });
      return true;
    }
  }
}

// src/panes/edit-callout-pane/section-preview.ts
var import_obsidian13 = require("obsidian");
var EditCalloutPanePreview = class {
  constructor(plugin, callout, viewOnly) {
    this.previewMarkdown = "Lorem ipsum dolor sit amet.";
    this.previewEditorEl = null;
    this.calloutHasIconReady = false;
    this.calloutId = callout.id;
    this.plugin = plugin;
    const frag = document.createDocumentFragment();
    this.sectionEl = frag.createDiv({
      cls: ["calloutmanager-preview-container", "calloutmanager-edit-callout-preview"]
    });
    this.preview = new IsolatedCalloutPreviewComponent(this.sectionEl, {
      id: callout.id,
      title: callout.id,
      icon: callout.icon,
      colorScheme: getCurrentThemeID2(plugin.app),
      content: (containerEl) => {
        containerEl.createEl("p", { text: this.previewMarkdown });
      }
    });
    if (!viewOnly) {
      this.makeEditable();
    }
  }
  makeEditable() {
    const contentEl = this.preview.contentEl;
    this.previewEditorEl = null;
    this.preview.calloutEl.addEventListener("click", () => {
      if (this.previewEditorEl != null) {
        return;
      }
      const height = contentEl.getBoundingClientRect().height;
      contentEl.empty();
      new import_obsidian13.TextAreaComponent(contentEl).setValue(this.previewMarkdown).setPlaceholder("Preview Markdown...").then((c) => {
        const inputEl = this.previewEditorEl = c.inputEl;
        inputEl.style.setProperty("height", `${height}px`);
        inputEl.classList.add("calloutmanager-preview-editor");
        inputEl.focus();
        inputEl.addEventListener("blur", () => {
          const value = c.getValue();
          this.previewEditorEl = null;
          this.previewMarkdown = value;
          this.changeContent(value);
        });
      });
    });
  }
  /**
   * Refreshes the callout preview's icon.
   * We need to do this after the preview is attached to DOM, as we can't get the correct icon until that happens.
   */
  refreshPreviewIcon() {
    var _a;
    const { iconEl, calloutEl } = this.preview;
    if (window.document.contains(this.sectionEl)) {
      const icon = window.getComputedStyle(calloutEl).getPropertyValue("--callout-icon").trim();
      const iconSvg = (_a = (0, import_obsidian13.getIcon)(icon)) != null ? _a : document.createElement("svg");
      iconEl.empty();
      iconEl.appendChild(iconSvg);
      this.calloutHasIconReady = true;
    }
  }
  /**
   * Changes the preview that is displayed inside the callout.
   *
   * @param markdown The markdown to render.
   */
  async changeContent(markdown) {
    const contentEl = this.preview.contentEl;
    contentEl.empty();
    try {
      await import_obsidian13.MarkdownRenderer.renderMarkdown(markdown, contentEl, "", void 0);
    } catch (ex) {
      contentEl.createEl("code").createEl("pre", { text: markdown });
    }
  }
  /**
   * Changes the settings for the callout.
   * This can be used to show the customized callout.
   *
   * @param settings The settings to use.
   */
  async changeSettings(settings) {
    const { preview } = this;
    const styles = calloutSettingsToCSS(this.calloutId, settings, currentCalloutEnvironment(this.plugin.app));
    preview.customStyleEl.textContent = styles;
    preview.resetStylePropertyOverrides();
    preview.removeStyles((el) => el.getAttribute("data-callout-manager") === "style-overrides");
    this.calloutHasIconReady = false;
    preview.removeStyles((el) => el.getAttribute("data-inject-id") === "callout-settings");
  }
  /**
   * Attaches the preview to a container.
   * @param containerEl The container element.
   */
  attach(containerEl) {
    containerEl.appendChild(this.sectionEl);
    if (!this.calloutHasIconReady) {
      this.refreshPreviewIcon();
    }
  }
};

// src/panes/edit-callout-pane/index.ts
var IMPOSSIBLE_CALLOUT_ID = "[not a real callout]";
var EditCalloutPane = class extends UIPane {
  constructor(plugin, id, viewOnly) {
    var _a, _b;
    super();
    this.plugin = plugin;
    this.viewOnly = viewOnly;
    this.title = { title: "Callout", subtitle: id };
    this.callout = (_a = plugin.callouts.get(id)) != null ? _a : {
      sources: [{ type: "custom" }],
      ...plugin.calloutResolver.getCalloutProperties(IMPOSSIBLE_CALLOUT_ID),
      id
    };
    this.previewSection = new EditCalloutPanePreview(plugin, this.callout, false);
    this.appearanceEditorContainerEl = document.createElement("div");
    this.appearanceEditorContainerEl.classList.add(
      "calloutmanager-edit-callout-section",
      "calloutmanager-edit-callout-appearance"
    );
    this.appearanceEditorContainerEl.createEl("h2", { text: "Appearance" });
    this.appearanceEditorEl = this.appearanceEditorContainerEl.createDiv();
    this.changeSettings((_b = plugin.getCalloutSettings(id)) != null ? _b : []);
  }
  changeAppearanceEditor(newAppearance) {
    const oldAppearance = this.appearance;
    this.appearance = newAppearance;
    if (newAppearance.type !== (oldAppearance == null ? void 0 : oldAppearance.type)) {
      this.appearanceEditor = new APPEARANCE_EDITORS[newAppearance.type]();
      Object.defineProperties(this.appearanceEditor, {
        nav: { get: () => this.nav },
        plugin: { value: this.plugin },
        containerEl: { value: this.appearanceEditorEl },
        setAppearance: { value: this.onSetAppearance.bind(this) }
      });
    }
    const { appearanceEditor } = this;
    appearanceEditor.appearance = newAppearance;
    appearanceEditor.callout = this.callout;
  }
  onSetAppearance(appearance) {
    this.changeAppearanceEditor(appearance);
    const newSettings = this.appearanceEditor.toSettings();
    const { callout } = this;
    const { calloutResolver } = this.plugin;
    this.plugin.setCalloutSettings(callout.id, newSettings);
    const { color, icon } = calloutResolver.getCalloutProperties(callout.id);
    callout.color = color;
    callout.icon = icon;
    this.previewSection.changeSettings(newSettings);
    this.appearanceEditor.callout = callout;
    this.appearanceEditorEl.empty();
    this.appearanceEditor.render();
    this.containerEl.empty();
    this.display();
  }
  /** @override */
  display() {
    const { containerEl, previewSection, appearanceEditorContainerEl } = this;
    containerEl.empty();
    previewSection.attach(containerEl);
    renderInfo(this.plugin.app, this.callout, containerEl);
    containerEl.appendChild(appearanceEditorContainerEl);
  }
  /** @override */
  displayControls() {
    const { callout, controlsEl } = this;
    if (!this.viewOnly && callout.sources.length === 1 && callout.sources[0].type === "custom") {
      new import_obsidian14.ButtonComponent(controlsEl).setIcon("lucide-trash").setTooltip("Delete Callout").onClick(() => {
        this.plugin.removeCustomCallout(callout.id);
        this.nav.close();
      }).then(({ buttonEl }) => buttonEl.classList.add("clickable-icon", "mod-warning"));
    }
  }
  /**
   * Changes the preview that is displayed inside the callout.
   *
   * @param markdown The markdown to render.
   */
  async changePreview(markdown) {
    return this.previewSection.changeContent(markdown);
  }
  /**
   * Changes the styles of the preview that is displayed inside the callout.
   *
   * @param markdown The markdown to render.
   */
  async changeSettings(settings) {
    this.changeAppearanceEditor(determineAppearanceType(settings));
    this.appearanceEditorEl.empty();
    this.appearanceEditor.render();
    await this.previewSection.changeSettings(settings);
  }
};
var APPEARANCE_EDITORS = {
  complex: ComplexAppearanceEditor,
  unified: UnifiedAppearanceEditor,
  "per-scheme": PerSchemeAppearanceEditor
};

// src/panes/create-callout-pane.ts
var CreateCalloutPane = class extends UIPane {
  constructor(plugin) {
    super();
    this.title = { title: "Callouts", subtitle: "New Callout" };
    this.plugin = plugin;
    const btnCreate = this.btnCreate = document.createElement("button");
    btnCreate.textContent = "Create";
    btnCreate.addEventListener("click", (evt) => {
      if (!this.areInputsValid()) {
        return;
      }
      const id = this.fieldIdEl.value;
      this.plugin.createCustomCallout(id);
      this.nav.replace(new EditCalloutPane(this.plugin, id, false));
    });
    this.fieldId = new import_obsidian15.Setting(document.createElement("div")).setHeading().setName("Callout Name").setDesc("This is how you will refer to your callout in Markdown.").addText((cmp) => {
      cmp.setPlaceholder("my-awesome-callout").onChange(() => this.validateInputs()).then(({ inputEl }) => this.fieldIdEl = inputEl).then(({ inputEl }) => inputEl.setAttribute("pattern", "[a-z-]{1,}")).then(({ inputEl }) => inputEl.setAttribute("required", "required"));
    });
    this.validateInputs();
  }
  validateInputs() {
    this.btnCreate.disabled = !this.areInputsValid();
  }
  areInputsValid() {
    if (!this.fieldIdEl.validity.valid)
      return false;
    return true;
  }
  /** @override */
  display() {
    const { containerEl } = this;
    containerEl.appendChild(this.fieldId.settingEl);
    containerEl.createDiv().appendChild(this.btnCreate);
  }
};

// src/panes/manage-callouts-pane.ts
var ManageCalloutsPane = class extends UIPane {
  constructor(plugin) {
    super();
    this.title = { title: "Callouts", subtitle: "Manage" };
    this.plugin = plugin;
    this.searchQuery = "";
    this.searchFilter = null;
    this.previewCache = [];
    this.viewOnly = false;
    const { searchErrorDiv, searchErrorQuery } = createEmptySearchResultDiv();
    this.searchErrorDiv = searchErrorDiv;
    this.searchErrorQuery = searchErrorQuery;
  }
  /**
   * Change the search query.
   * @param query The search query.
   */
  search(query) {
    const split = query.split(":", 2);
    let prefix = "id", search = query;
    if (split.length === 2) {
      prefix = split[0];
      search = split[1].trim();
    }
    this.searchFilter = this.prepareSearch(search, prefix);
    this.searchQuery = query;
    this.searchErrorQuery.textContent = search;
    this.display();
  }
  /**
   * Prepares the search filter function.
   *
   * @param query The query.
   * @param queryPrefix The query prefix (type of query).
   *
   * @returns The search filter function.
   */
  prepareSearch(query, queryPrefix) {
    if (queryPrefix === "id") {
      const fuzzy = (0, import_obsidian16.prepareFuzzySearch)(query.toLowerCase());
      return (callout) => fuzzy(callout.id);
    }
    if (queryPrefix === "icon") {
      const fuzzy = (0, import_obsidian16.prepareFuzzySearch)(query.toLowerCase());
      return (callout) => fuzzy(callout.icon.toLowerCase());
    }
    if (queryPrefix === "from") {
      const queryLC = query.toLowerCase();
      const queryIsBuiltin = queryLC === "obsidian" || queryLC === "builtin" || queryLC === "built-in";
      const fuzzy = (0, import_obsidian16.prepareFuzzySearch)(queryLC);
      const hasSnippetWithQueryAsId = this.plugin.callouts.snippets.keys().find((id) => id.toLowerCase() === queryLC) !== void 0;
      return (callout) => {
        let result = null;
        if (query === "")
          return { matches: [], score: 0 };
        for (const source of callout.sources) {
          if (hasSnippetWithQueryAsId) {
            if (source.type === "snippet" && source.snippet.toLowerCase() === queryLC)
              return { matches: [], score: -1 };
            continue;
          }
          switch (source.type) {
            case "builtin":
              if (queryIsBuiltin)
                return { matches: [], score: -1 };
              break;
            case "custom":
              if (queryLC === "custom")
                return { matches: [], score: -1 };
              break;
            case "theme":
              if (queryLC === "theme")
                return { matches: [], score: -1 };
              break;
            case "snippet": {
              const snippetLC = source.snippet.toLowerCase();
              if (snippetLC === queryLC)
                return { matches: [], score: -1 };
              const fuzzily = fuzzy(snippetLC);
              if (fuzzily != null && (result == null || fuzzily.score < result.score)) {
                result = fuzzily;
              }
            }
          }
        }
        return result;
      };
    }
    return () => null;
  }
  /**
   * Filter and sort callout previews based on the fuzzy search query.
   * If there is no search query, previews will be sorted based on color.
   *
   * @param previews The previews to filter and sort.
   * @returns The filtered and sorted previews.
   */
  filterAndSort(previews) {
    const { searchFilter } = this;
    if (searchFilter == null) {
      return previews.sort(comparePreviewByColor);
    }
    const filterMapped = [];
    for (const preview of previews) {
      const result = searchFilter(preview);
      if (result != null) {
        filterMapped.push([preview, result]);
      }
    }
    filterMapped.sort(([aPreview, aResults], [bPreview, bResults]) => {
      const scoreDiff = bResults.score - aResults.score;
      if (scoreDiff != 0)
        return scoreDiff;
      return comparePreviewByColor(aPreview, bPreview);
    });
    return filterMapped.map(([preview, _]) => preview);
  }
  /**
   * Refresh the callout previews.
   * This regenerates the previews and their metadata from the list of callouts known to the plugin.
   */
  refreshPreviews() {
    var _a;
    const editButtonContent = (_a = this.viewOnly ? (0, import_obsidian16.getIcon)("lucide-view") : (0, import_obsidian16.getIcon)("lucide-edit")) != null ? _a : document.createTextNode("Edit Callout");
    const editButtonHandler = (evt) => {
      let id = null;
      for (let target = evt.targetNode; target != null && id == null; target = target == null ? void 0 : target.parentElement) {
        if (target instanceof Element) {
          id = target.getAttribute("data-callout-manager-callout");
        }
      }
      if (id != null) {
        this.nav.open(new EditCalloutPane(this.plugin, id, this.viewOnly));
      }
    };
    this.previewCache = [];
    for (const callout of this.plugin.callouts.values()) {
      const calloutContainerEl = document.createElement("div");
      calloutContainerEl.classList.add("calloutmanager-preview-container");
      calloutContainerEl.setAttribute("data-callout-manager-callout", callout.id);
      this.previewCache.push(createPreview(callout, calloutContainerEl));
      calloutContainerEl.classList.add("calloutmanager-preview-container-with-button");
      const editButton = calloutContainerEl.createEl("button");
      editButton.appendChild(editButtonContent.cloneNode(true));
      editButton.addEventListener("click", editButtonHandler);
    }
  }
  /** @override */
  display() {
    const { containerEl } = this;
    const previews = this.filterAndSort(this.previewCache);
    containerEl.empty();
    for (const preview of previews) {
      containerEl.appendChild(preview.calloutContainerEl);
    }
    if (previews.length === 0) {
      containerEl.appendChild(this.searchErrorDiv);
    }
  }
  /** @override */
  displayControls() {
    const { controlsEl } = this;
    new import_obsidian16.TextComponent(controlsEl).setValue(this.searchQuery).setPlaceholder("Filter callouts...").onChange(this.search.bind(this));
    if (!this.viewOnly) {
      new import_obsidian16.ButtonComponent(controlsEl).setIcon("lucide-plus").setTooltip("New Callout").onClick(() => this.nav.open(new CreateCalloutPane(this.plugin))).then(({ buttonEl }) => buttonEl.classList.add("clickable-icon"));
    }
  }
  /** @override */
  restoreState(state) {
    this.refreshPreviews();
  }
  /** @override */
  onReady() {
    this.refreshPreviews();
  }
};
function createPreview(callout, calloutContainerEl) {
  const { icon, id } = callout;
  const color = getColorFromCallout(callout);
  return {
    sources: callout.sources,
    icon,
    id,
    calloutContainerEl,
    colorValid: color != null,
    colorHue: color == null ? 0 : toHSV(color).h,
    preview: new CalloutPreviewComponent(calloutContainerEl, {
      id,
      icon,
      color: color != null ? color : void 0
    })
  };
}
function comparePreviewByColor(a, b) {
  if (a.colorValid && !b.colorValid)
    return -1;
  if (b.colorValid && !a.colorValid)
    return 1;
  return a.colorHue - b.colorHue;
}
function createEmptySearchResultDiv() {
  let searchErrorQuery;
  const searchErrorDiv = document.createElement("div");
  searchErrorDiv.className = "calloutmanager-centerbox";
  const contentEl = searchErrorDiv.createDiv({ cls: "calloutmanager-search-error" });
  contentEl.createEl("h2", { text: "No callouts found." });
  contentEl.createEl("p", void 0, (el) => {
    el.createSpan({ text: "Your search query " });
    searchErrorQuery = el.createEl("code", { text: "" });
    el.createSpan({ text: " did not return any results." });
  });
  contentEl.createDiv({ cls: "calloutmanager-search-error-suggestions" }, (el) => {
    el.createDiv({ text: "Try searching:" });
    el.createEl("ul", void 0, (el2) => {
      el2.createEl("li", { text: "By name: " }, (el3) => {
        el3.createEl("code", { text: "warning" });
      });
      el2.createEl("li", { text: "By icon: " }, (el3) => {
        el3.createEl("code", { text: "icon:check" });
      });
      el2.createEl("li", { text: "Built-in callouts: " }, (el3) => {
        el3.createEl("code", { text: "from:obsidian" });
      });
      el2.createEl("li", { text: "Theme callouts: " }, (el3) => {
        el3.createEl("code", { text: "from:theme" });
      });
      el2.createEl("li", { text: "Snippet callouts: " }, (el3) => {
        el3.createEl("code", { text: "from:my snippet" });
      });
      el2.createEl("li", { text: "Custom callouts: " }, (el3) => {
        el3.createEl("code", { text: "from:custom" });
      });
    });
  });
  return { searchErrorDiv, searchErrorQuery };
}

// src/panes/manage-plugin-pane.ts
var import_obsidian17 = require("obsidian");
var ManagePluginPane = class extends UIPane {
  constructor(plugin) {
    super();
    this.title = "Callout Manager Settings";
    this.plugin = plugin;
  }
  /** @override */
  display() {
    const { containerEl, plugin } = this;
    new import_obsidian17.Setting(containerEl).setName("Manage Callouts").setDesc("Create or edit Markdown callouts.").addButton((btn) => {
      btn.setButtonText("Manage Callouts");
      btn.onClick(() => this.nav.open(new ManageCalloutsPane(plugin)));
    });
    containerEl.createEl("h2", { text: "Callout Detection" });
    new import_obsidian17.Setting(containerEl).setName("Obsidian").setDesc(
      (() => {
        const desc = document.createDocumentFragment();
        const container = desc.createDiv();
        container.createDiv({
          text: plugin.settings.calloutDetection.obsidianFallbackForced ? "Include the built-in Obsidian callouts." : "Find built-in Obsidian callouts."
        });
        if (!plugin.cssWatcher.isObsidianStylesheetSupported() && !plugin.settings.calloutDetection.obsidianFallbackForced) {
          container.createDiv({
            cls: "mod-warning",
            text: "Your current platform does not support automatic detection. A fallback list will be used."
          });
        }
        return desc;
      })()
    ).addToggle((setting) => {
      setting.setValue(plugin.settings.calloutDetection.obsidian).onChange((v) => {
        plugin.settings.calloutDetection.obsidian = v;
        plugin.saveSettings();
        plugin.refreshCalloutSources();
      });
    });
    new import_obsidian17.Setting(containerEl).setName("Theme").setDesc("Find theme-provided callouts.").addToggle((setting) => {
      setting.setValue(plugin.settings.calloutDetection.theme).onChange((v) => {
        plugin.settings.calloutDetection.theme = v;
        plugin.saveSettings();
        plugin.refreshCalloutSources();
      });
    });
    new import_obsidian17.Setting(containerEl).setName("Snippet").setDesc("Find callouts in custom CSS snippets.").addToggle((setting) => {
      setting.setValue(plugin.settings.calloutDetection.snippet).onChange((v) => {
        plugin.settings.calloutDetection.snippet = v;
        plugin.saveSettings();
        plugin.refreshCalloutSources();
      });
    });
    containerEl.createEl("h2", { text: "Reset" });
    new import_obsidian17.Setting(containerEl).setName("Reset Callout Settings").setDesc("Reset all the changes you made to callouts.").addButton(
      withConfirm((btn) => {
        btn.setButtonText("Reset").onClick(() => {
          this.plugin.settings.callouts.settings = {};
          this.plugin.saveSettings();
          this.plugin.applyStyles();
          btn.setButtonText("Reset").setDisabled(true);
        });
      })
    );
    new import_obsidian17.Setting(containerEl).setName("Reset Custom Callouts").setDesc("Removes all the custom callouts you created.").addButton(
      withConfirm((btn) => {
        btn.setButtonText("Reset").onClick(() => {
          const { settings } = this.plugin;
          for (const custom of settings.callouts.custom) {
            delete settings.callouts.settings[custom];
          }
          settings.callouts.custom = [];
          this.plugin.saveSettings();
          this.plugin.callouts.custom.clear();
          this.plugin.applyStyles();
          this.plugin.refreshCalloutSources();
          btn.setButtonText("Reset").setDisabled(true);
        });
      })
    );
  }
};
function withConfirm(callback) {
  let onClickHandler = void 0;
  let resetButtonClicked = false;
  return (btn) => {
    btn.setWarning().onClick(() => {
      if (!resetButtonClicked) {
        resetButtonClicked = true;
        btn.setButtonText("Confirm");
        return;
      }
      if (onClickHandler != void 0) {
        onClickHandler();
      }
    });
    btn.onClick = (handler) => {
      onClickHandler = handler;
      return btn;
    };
    callback(btn);
  };
}

// src/settings.ts
function defaultSettings() {
  return {
    callouts: {
      custom: [],
      settings: {}
    },
    calloutDetection: {
      obsidianFallbackForced: false,
      obsidian: true,
      theme: true,
      snippet: true
    }
  };
}
function mergeSettings(into, from) {
  var _a;
  return Object.assign(into, {
    ...from,
    calloutDetection: {
      ...into.calloutDetection,
      ...(_a = from == null ? void 0 : from.calloutDetection) != null ? _a : {}
    }
  });
}

// src/main.ts
var CalloutManagerPlugin = class extends import_obsidian18.Plugin {
  /** @override */
  async onload() {
    this.apiHandles = /* @__PURE__ */ new Map();
    await this.loadSettings();
    await this.saveSettings();
    const { settings } = this;
    this.calloutResolver = new CalloutResolver();
    this.register(() => this.calloutResolver.unload());
    this.callouts = new CalloutCollection((id) => {
      const { icon, color } = this.calloutResolver.getCalloutProperties(id);
      console.debug("Resolved Callout:", id, { icon, color });
      return {
        id,
        icon,
        color
      };
    });
    this.callouts.custom.add(...settings.callouts.custom);
    this.cssApplier = createCustomStyleSheet(this.app, this);
    this.cssApplier.setAttribute("data-callout-manager", "style-overrides");
    this.register(this.cssApplier);
    this.applyStyles();
    this.cssWatcher = new StylesheetWatcher(this.app, settings.calloutDetection.obsidianFallbackForced);
    this.cssWatcher.on("add", this.updateCalloutSource.bind(this));
    this.cssWatcher.on("change", this.updateCalloutSource.bind(this));
    this.cssWatcher.on("remove", this.removeCalloutSource.bind(this));
    this.cssWatcher.on("checkComplete", () => this.maybeRefreshCalloutBuiltinsWithFallback());
    this.cssWatcher.on("checkComplete", (anyChanges) => {
      if (anyChanges) {
        this.emitApiEventChange();
      }
    });
    this.app.workspace.onLayoutReady(() => {
      this.register(this.cssWatcher.watch());
    });
    this.registerEvent(
      this.app.workspace.on("css-change", () => {
        this.calloutResolver.reloadStyles();
        this.applyStyles();
      })
    );
    this.settingTab = new UISettingTab(this, () => new ManagePluginPane(this));
    this.addSettingTab(this.settingTab);
    this.addCommand({
      id: "manage-callouts",
      name: "Edit callouts",
      callback: () => {
        this.settingTab.openWithPane(new ManageCalloutsPane(this));
      }
    });
  }
  async loadSettings() {
    this.settings = mergeSettings(defaultSettings(), await this.loadData());
  }
  async saveSettings() {
    await this.saveData(this.settings);
  }
  /**
   * Takes in a stylesheet from the watcher and updates the callout collection.
   * @param ss The stylesheet.
   */
  updateCalloutSource(ss) {
    const callouts = getCalloutsFromCSS(ss.styles);
    const { calloutDetection } = this.settings;
    switch (ss.type) {
      case "obsidian":
        if (calloutDetection.obsidian === true && !calloutDetection.obsidianFallbackForced) {
          this.callouts.builtin.set(callouts);
        }
        return;
      case "theme":
        if (calloutDetection.theme) {
          this.callouts.theme.set(ss.theme, callouts);
        }
        return;
      case "snippet":
        if (calloutDetection.snippet) {
          this.callouts.snippets.set(ss.snippet, callouts);
        }
        return;
    }
  }
  /**
   * Forces the callout sources to be refreshed.
   * This is used to re-detect the sources when settings are changed.
   */
  refreshCalloutSources() {
    this.callouts.snippets.clear();
    this.callouts.theme.delete();
    this.callouts.builtin.set([]);
    this.cssWatcher.checkForChanges(true).then(() => {
      this.maybeRefreshCalloutBuiltinsWithFallback();
    });
  }
  /**
   * Create a custom callout and add it to Obsidian.
   * @param id The custom callout ID.
   */
  createCustomCallout(id) {
    const { callouts, settings } = this;
    callouts.custom.add(id);
    settings.callouts.custom = callouts.custom.keys();
    this.saveSettings();
    this.emitApiEventChange(id);
  }
  /**
   * Delete a custom callout.
   * @param id The custom callout ID.
   */
  removeCustomCallout(id) {
    const { callouts, settings } = this;
    callouts.custom.delete(id);
    settings.callouts.custom = callouts.custom.keys();
    this.saveSettings();
    this.emitApiEventChange(id);
  }
  /**
   * Gets the custom settings for a callout.
   *
   * @param id The callout ID.
   * @returns The custom settings, or undefined if there are none.
   */
  getCalloutSettings(id) {
    const calloutSettings = this.settings.callouts.settings;
    if (!Object.prototype.hasOwnProperty.call(calloutSettings, id)) {
      return void 0;
    }
    return calloutSettings[id];
  }
  /**
   * Sets the custom settings for a callout.
   *
   * @param id The callout ID.
   * @param settings The callout settings.
   */
  setCalloutSettings(id, settings) {
    const calloutSettings = this.settings.callouts.settings;
    if (settings === void 0) {
      delete calloutSettings[id];
    } else {
      calloutSettings[id] = settings;
    }
    this.saveSettings();
    this.applyStyles();
    this.callouts.invalidate(id);
    this.emitApiEventChange(id);
  }
  /**
   * Generates the stylesheet for the user's custom callout settings and applies it to the page and the callout
   * resolver's custom stylesheet.
   */
  applyStyles() {
    const env = currentCalloutEnvironment(this.app);
    const css = [];
    for (const [id, settings] of Object.entries(this.settings.callouts.settings)) {
      css.push(calloutSettingsToCSS(id, settings, env));
    }
    const stylesheet = css.join("\n\n");
    this.cssApplier.css = stylesheet;
    this.calloutResolver.customStyleEl.textContent = stylesheet;
  }
  /**
   * If the fallback list is forced or obsidian stylesheet detection is unsupported,
   * add the embedded fallback list to the callout collection.
   */
  maybeRefreshCalloutBuiltinsWithFallback() {
    const { calloutDetection } = this.settings;
    if (!calloutDetection.obsidian) {
      return;
    }
    if (calloutDetection.obsidianFallbackForced || !this.cssWatcher.isObsidianStylesheetSupported()) {
      this.callouts.builtin.set(callout_fallback_obsidian_default);
    }
  }
  /**
   * Takes in a stylesheet from the watcher and removes its callouts from the callout collection.
   * @param ss The stylesheet.
   */
  removeCalloutSource(ss) {
    switch (ss.type) {
      case "obsidian":
        this.callouts.builtin.set([]);
        return;
      case "theme":
        this.callouts.theme.delete();
        return;
      case "snippet":
        this.callouts.snippets.delete(ss.snippet);
        return;
    }
  }
  /**
   * Creates (or gets) an instance of the Callout Manager API for a plugin.
   * If the plugin is undefined, only trivial functions are available.
   *
   * @param version The API version.
   * @param consumerPlugin The plugin using the API.
   *
   * @internal
   */
  newApiHandle(version, consumerPlugin, cleanupFunc) {
    if (version !== "v1")
      throw new Error(`Unsupported Callout Manager API: ${version}`);
    if (consumerPlugin == null) {
      return new CalloutManagerAPI_V1(this, void 0);
    }
    const existing = this.apiHandles.get(consumerPlugin);
    if (existing != null) {
      return existing;
    }
    consumerPlugin.register(cleanupFunc);
    const handle = new CalloutManagerAPI_V1(this, consumerPlugin);
    this.apiHandles.set(consumerPlugin, handle);
    return handle;
  }
  destroyApiHandle(version, consumerPlugin) {
    if (version !== "v1")
      throw new Error(`Unsupported Callout Manager API: ${version}`);
    const handle = this.apiHandles.get(consumerPlugin);
    if (handle == null)
      return;
    handle.destroy();
    this.apiHandles.delete(consumerPlugin);
  }
  emitApiEventChange(callout) {
    for (const handle of this.apiHandles.values()) {
      handle._emit("change");
    }
  }
};
