UNPKG

zotero-plugin-toolkit

Version:
2,172 lines 66.9 kB
import * as React from "react";

//#region src/typings/basic.d.ts
declare type FunctionNamesOf<T> = keyof FunctionsOf<T>;
declare type FunctionsOf<T> = { [K in keyof T as T[K] extends Function ? K : never]: T[K] };
//#endregion
//#region src/basic.d.ts
/**
 * Basic APIs with Zotero 6 & newer (7) compatibility.
 * See also https://www.zotero.org/support/dev/zotero_7_for_developers
 */
declare class BasicTool {
  /**
   * configurations.
   */
  protected _basicOptions: BasicOptions;
  protected _console?: Console;
  /**
   * @deprecated Use `patcherManager` instead.
   */
  protected readonly patchSign: string;
  static _version: string;
  /**
   * Get version - checks subclass first, then falls back to parent
   */
  get _version(): string;
  get basicOptions(): BasicOptions;
  /**
   *
   * @param data Pass an BasicTool instance to copy its options.
   */
  constructor(data?: BasicTool | BasicOptions);
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero" | "zotero"): _ZoteroTypes.Zotero;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "ZoteroPane" | "ZoteroPane_Local"): _ZoteroTypes.ZoteroPane;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_Tabs"): _ZoteroTypes.Zotero_Tabs;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_File_Interface"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_File_Exporter"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_LocateMenu"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_Report_Interface"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_Timeline_Interface"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "Zotero_Tooltip"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "ZoteroContextPane"): _ZoteroTypes.ZoteroContextPane;
  /**
   * @alpha
   * @param k
   */
  getGlobal(k: "ZoteroItemPane"): any;
  /**
   * @alpha
   * @param k
   */
  getGlobal<K extends keyof typeof globalThis, GLOBAL extends typeof globalThis>(k: K): GLOBAL[K];
  /**
   * Get global variables.
   * @param k Global variable name, `Zotero`, `ZoteroPane`, `window`, `document`, etc.
   */
  getGlobal(k: string): any;
  /**
   * If it's an XUL element
   * @param elem
   */
  isXULElement(elem: Element): boolean;
  /**
   * Create an XUL element
   *
   * For Zotero 6, use `createElementNS`;
   *
   * For Zotero 7+, use `createXULElement`.
   * @param doc
   * @param type
   * @example
   * Create a `<menuitem>`:
   * ```ts
   * const compat = new ZoteroCompat();
   * const doc = compat.getWindow().document;
   * const elem = compat.createXULElement(doc, "menuitem");
   * ```
   */
  createXULElement(doc: Document, type: string): XULElement;
  /**
   * Output to both Zotero.debug and console.log
   * @param data e.g. string, number, object, ...
   */
  log(...data: any): void;
  /**
   * Patch a function
   * @deprecated Use {@link PatchHelper} instead.
   * @param object The owner of the function
   * @param funcSign The signature of the function(function name)
   * @param ownerSign The signature of patch owner to avoid patching again
   * @param patcher The new wrapper of the patched function
   */
  patch<T, K extends FunctionNamesOf<T>>(object: T, funcSign: K, ownerSign: string, patcher: (fn: T[K]) => T[K]): void;
  /**
   * Add a Zotero event listener callback
   * @param type Event type
   * @param callback Event callback
   */
  addListenerCallback<T extends keyof ListenerCallbackMap>(type: T, callback: ListenerCallbackMap[T]): void;
  /**
   * Remove a Zotero event listener callback
   * @param type Event type
   * @param callback Event callback
   */
  removeListenerCallback<T extends keyof ListenerCallbackMap>(type: T, callback: ListenerCallbackMap[T]): void;
  /**
   * Remove all Zotero event listener callbacks when the last callback is removed.
   */
  protected _ensureRemoveListener(): void;
  /**
   * Ensure the main window listener is registered.
   */
  protected _ensureMainWindowListener(): void;
  /**
   * Ensure the plugin listener is registered.
   */
  protected _ensurePluginListener(): void;
  updateOptions(source?: BasicTool | BasicOptions): this;
  static getZotero(): _ZoteroTypes.Zotero;
}
interface BasicOptions {
  log: {
    readonly _type: "toolkitlog";
    disableConsole: boolean;
    disableZLog: boolean;
    prefix: string;
  };
  debug: {
    disableDebugBridgePassword: boolean;
    password: string;
  };
  _debug?: BasicOptions["debug"];
  api: {
    pluginID: string;
  };
  listeners: {
    _mainWindow?: any;
    _plugin?: _ZoteroTypes.Plugins.observer;
    callbacks: { [K in keyof ListenerCallbackMap]: Set<ListenerCallbackMap[K]> };
  };
}
declare abstract class ManagerTool extends BasicTool {
  abstract register(...data: any[]): any;
  abstract unregister(...data: any[]): any;
  /**
   * Unregister everything
   */
  abstract unregisterAll(): any;
  protected _ensureAutoUnregisterAll(): void;
}
declare function unregister(tools: {
  [key: string | number]: any;
}): void;
declare function makeHelperTool<T extends typeof HelperTool>(cls: T, options: BasicTool | BasicOptions): T;
declare function makeHelperTool<T>(cls: T, options: BasicTool | BasicOptions): T;
declare function _importESModule(path: string): any;
declare interface ListenerCallbackMap {
  onMainWindowLoad: (win: Window) => void;
  onMainWindowUnload: (win: Window) => void;
  onPluginUnload: (...args: Parameters<NonNullable<_ZoteroTypes.Plugins.observer["shutdown"]>>) => void;
}
declare class HelperTool {
  constructor(...args: any);
  updateOptions: BasicTool["updateOptions"];
}
//#endregion
//#region src/helpers/clipboard.d.ts
/**
 * Copy helper for text/richtext/image.
 *
 * @example
 * Copy plain text
 * ```ts
 * new ClipboardHelper().addText("plain", "text/unicode").copy();
 * ```
 * @example
 * Copy plain text & rich text
 * ```ts
 * new ClipboardHelper().addText("plain", "text/unicode")
 *                     .addText("<h1>rich text</h1>", "text/html")
 *                     .copy();
 * ```
 * @example
 * Copy plain text, rich text & image
 * ```ts
 * new ClipboardHelper().addText("plain", "text/unicode")
 *                     .addText("<h1>rich text</h1>", "text/html")
 *                     .addImage("data:image/png;base64,...")
 *                     .copy();
 * ```
 */
declare class ClipboardHelper extends BasicTool {
  private transferable;
  private clipboardService;
  private filePath;
  constructor();
  addText(source: string, type?: "text/html" | "text/plain" | "text/unicode"): this;
  addImage(source: string): this;
  addFile(path: string): this;
  copy(): this;
}
//#endregion
//#region src/tools/ui.d.ts
/**
 * UI APIs. Create elements and manage them.
 */
declare class UITool extends BasicTool {
  /**
   * UITool options
   */
  protected _basicOptions: UIOptions;
  get basicOptions(): UIOptions;
  /**
   * Store elements created with this instance
   *
   * @remarks
   * > What is this for?
   *
   * In bootstrap plugins, elements must be manually maintained and removed on exiting.
   *
   * This API does this for you.
   */
  protected elementCache: WeakRef<Element>[];
  constructor(base?: BasicTool | BasicOptions);
  /**
   * Remove all elements created by `createElement`.
   *
   * @remarks
   * > What is this for?
   *
   * In bootstrap plugins, elements must be manually maintained and removed on exiting.
   *
   * This API does this for you.
   */
  unregisterAll(): void;
  /**
   * Create `DocumentFragment`.
   * @param doc
   * @param tagName
   * @param props
   * @example
   * ```ts
   * const frag: DocumentFragment = ui.createElement(
   *   document, "fragment",
   *   {
   *     children:
   *     [
   *       { tag: "h1", properties: { innerText: "Hello World!" } }
   *     ]
   *   }
   * );
   * ```
   */
  createElement(doc: Document, tagName: "fragment", props?: FragmentElementProps): DocumentFragment;
  /**
   * Create `HTMLElement`.
   * @param doc
   * @param tagName
   * @param props See {@link ElementProps }
   * @example
   * ```ts
   * const div: HTMLDivElement = ui.createElement(document, "div");
   * ```
   * @example
   * Attributes(for `elem.setAttribute()`), properties(for `elem.prop=`), listeners, and children.
   * ```ts
   * const div: HTMLDivElement = ui.createElement(
   *   document, "div",
   *   {
   *     id: "hi-div",
   *     skipIfExists: true,
   *     listeners:
   *     [
   *       { type: "click", listener: (e)=>ui.log("Clicked!") }
   *     ],
   *     children:
   *     [
   *       { tag: "h1", properties: { innerText: "Hello World!" } },
   *       { tag: "a", attributes: { href: "https://www.zotero.org" } },
   *     ]
   *   }
   * );
   * ```
   */
  createElement<HTML_TAG extends keyof HTMLElementTagNameMap, T extends HTMLElementTagNameMap[HTML_TAG]>(doc: Document, tagName: HTML_TAG, props?: HTMLElementProps): T;
  /**
   * Create `XULElement`.
   * @see ElementProps
   * @param doc
   * @param tagName
   * @param props See {@link ElementProps }
   * @example
   * ```ts
   * const menuitem: XULMenuItem = ui.createElement(document, "menuitem", { attributes: { label: "Click Me!" } });
   * ```
   */
  createElement<XUL_TAG extends keyof XULElementTagNameMap, T extends XULElementTagNameMap[XUL_TAG]>(doc: Document, tagName: XUL_TAG, props?: XULElementProps): T;
  /**
   * Create `SVGElement`
   * @param doc
   * @param tagName
   * @param props See {@link ElementProps }
   */
  createElement<SVG_TAG extends keyof SVGElementTagNameMap, T extends SVGElementTagNameMap[SVG_TAG]>(doc: Document, tagName: SVG_TAG, props?: SVGElementProps): T;
  /**
   * Create Element
   * @param doc
   * @param tagName
   * @param props See {@link ElementProps }
   */
  createElement(doc: Document, tagName: string, props?: ElementProps): HTMLElement | XULElement | SVGElement;
  /**
   * @deprecated
   * @param doc target document, e.g. Zotero main window.document
   * @param tagName element tag name, e.g. `hbox`, `div`
   * @param namespace default "html"
   * @param enableElementRecord If current element will be recorded and maintained by toolkit. If not set, use this.enableElementRecordGlobal
   */
  createElement(doc: Document, tagName: string, namespace?: "html" | "svg" | "xul", enableElementRecord?: boolean): HTMLElement | XULElement | SVGElement | DocumentFragment;
  /**
   * Append element(s) to a node.
   * @param properties See {@link ElementProps}
   * @param container The parent node to append to.
   * @returns A Node that is the appended child (aChild),
   *          except when aChild is a DocumentFragment,
   *          in which case the empty DocumentFragment is returned.
   */
  appendElement(properties: TagElementProps, container: Element): Node;
  /**
   * Inserts a node before a reference node as a child of its parent node.
   * @param properties See {@link ElementProps}
   * @param referenceNode The node before which newNode is inserted.
   * @returns Node
   */
  insertElementBefore(properties: TagElementProps, referenceNode: Element): Node | undefined;
  /**
   * Replace oldNode with a new one.
   * @param properties See {@link ElementProps}
   * @param oldNode The child to be replaced.
   * @returns The replaced Node. This is the same node as oldChild.
   */
  replaceElement(properties: ElementProps & {
    tag: string;
  }, oldNode: Element): Node | undefined;
  /**
   * Parse XHTML to XUL fragment. For Zotero 6.
   *
   * To load preferences from a Zotero 7's `.xhtml`, use this method to parse it.
   * @param str xhtml raw text
   * @param entities dtd file list ("chrome://xxx.dtd")
   * @param defaultXUL true for default XUL namespace
   */
  parseXHTMLToFragment(str: string, entities?: string[], defaultXUL?: boolean): DocumentFragment;
}
interface UIOptions extends BasicOptions {
  ui: {
    /**
     * Whether to record elements created with `createElement`.
     */
    enableElementRecord: boolean;
    /**
     * Wether to log the `ElementProps` parameter in `createElement`.
     */
    enableElementJSONLog: boolean;
    /**
     * Wether to log the DOM node mounted by `createElement`.
     */
    enableElementDOMLog: boolean;
  };
}
/**
 * `props` of `UITool.createElement`. See {@link UITool}
 */
interface ElementProps {
  /**
   * tagName
   */
  tag?: string;
  /**
   * id
   */
  id?: string;
  /**
   * xul | html | svg
   */
  namespace?: string;
  /**
   * classList
   */
  classList?: Array<string>;
  /**
   * styles
   */
  styles?: Partial<CSSStyleDeclaration>;
  /**
   * Set with `elem.prop =`
   */
  properties?: {
    [key: string]: unknown;
  };
  /**
   * @deprecated Use `properties`
   */
  directAttributes?: {
    [key: string]: string | boolean | number | null | undefined;
  };
  /**
   * Set with `elem.setAttribute()`
   */
  attributes?: {
    [key: string]: string | boolean | number | null | undefined;
  };
  /**
   * Event listeners
   */
  listeners?: Array<{
    type: string;
    listener: EventListenerOrEventListenerObject | ((e: Event) => void) | null | undefined;
    options?: boolean | AddEventListenerOptions;
  }>;
  /**
   * Child elements. Will be created and appended to this element.
   */
  children?: Array<TagElementProps>;
  /**
   * Set true to check if the element exists using `id`. If exists, return this element and do not do anything.
   */
  ignoreIfExists?: boolean;
  /**
   * Set true to check if the element exists using `id`. If exists, skip element creation and continue with props/attrs/children.
   */
  skipIfExists?: boolean;
  /**
   * Set true to check if the element exists using `id`. If exists, remove and re-create it, then continue with props/attrs/children.
   */
  removeIfExists?: boolean;
  /**
   * Existence check will be processed under this element, default `document`
   */
  checkExistenceParent?: HTMLElement;
  /**
   * Custom check hook. If it returns false, return undefined and do not do anything.
   * @param doc
   * @param options
   */
  customCheck?: (doc: Document, options: ElementProps) => boolean;
  /**
   * @deprecated Use `children`
   */
  subElementOptions?: Array<TagElementProps>;
  /**
   * Enable elements to be recorded by the toolkit so it can be removed when calling `unregisterAll`.
   */
  enableElementRecord?: boolean;
  /**
   * Enable elements to be printed to console & Zotero.debug.
   */
  enableElementJSONLog?: boolean;
  /**
   * Enable elements to be printed to console & Zotero.debug.
   */
  enableElementDOMLog?: boolean;
}
interface TagElementProps extends ElementProps {
  tag: string;
}
interface HTMLElementProps extends Exclude<ElementProps, {
  tag: any;
}> {
  namespace?: "html";
}
interface SVGElementProps extends Exclude<ElementProps, {
  tag: any;
}> {
  namespace?: "svg";
}
interface XULElementProps extends Exclude<ElementProps, {
  tag: any;
}> {
  namespace?: "xul";
}
interface FragmentElementProps {
  children?: Array<ElementProps>;
}
interface XULElementTagNameMap {
  action: XULElement;
  arrowscrollbox: XULElement;
  bbox: XULBoxElement;
  binding: XULElement;
  bindings: XULElement;
  box: XULElement;
  broadcaster: XULElement;
  broadcasterset: XULElement;
  button: XULButtonElement;
  browser: XULBrowserElement;
  checkbox: XULCheckboxElement;
  caption: XULElement;
  colorpicker: XULColorPickerElement;
  column: XULElement;
  columns: XULElement;
  commandset: XULElement;
  command: XULCommandElement;
  conditions: XULElement;
  content: XULElement;
  deck: XULDeckElement;
  description: XULDescriptionElement;
  dialog: XULElement;
  dialogheader: XULElement;
  editor: XULElement;
  grid: XULElement;
  grippy: XULGrippyElement;
  groupbox: XULGroupBoxElement;
  hbox: XULBoxElement;
  iframe: XULElement;
  image: XULElement;
  key: XULElement;
  keyset: XULElement;
  label: XULLabelElement;
  listbox: XULElement;
  listcell: XULElement;
  listcol: XULElement;
  listcols: XULElement;
  listhead: XULElement;
  listheader: XULElement;
  listitem: XULListItemElement;
  member: XULElement;
  menu: XULMenuElement;
  menubar: XULMenuBarElement;
  menuitem: XULMenuItemElement;
  menulist: XULMenuListElement;
  menupopup: XULMenuPopupElement;
  menuseparator: XULMenuSeparatorElement;
  observes: XULElement;
  overlay: XULElement;
  page: XULElement;
  popup: XULPopupElement;
  popupset: XULElement;
  preference: XULElement;
  preferences: XULElement;
  prefpane: XULElement;
  prefwindow: XULElement;
  progressmeter: XULProgressMeterElement;
  radio: XULRadioElement;
  radiogroup: XULRadioGroupElement;
  resizer: XULElement;
  richlistbox: XULElement;
  richlistitem: XULElement;
  row: XULElement;
  rows: XULElement;
  rule: XULElement;
  script: XULElement;
  scrollbar: XULScrollBarElement;
  scrollbox: XULElement;
  scrollcorner: XULElement;
  separator: XULSeparatorElement;
  spacer: XULSpacerElement;
  splitter: XULSplitterElement;
  stack: XULElement;
  statusbar: XULStatusBarElement;
  statusbarpanel: XULStatusBarPanelElement;
  stringbundle: XULElement;
  stringbundleset: XULElement;
  tab: XULTabElement;
  tabbrowser: XULElement;
  tabbox: XULTabBoxElement;
  tabpanel: XULTabPanelElement;
  tabpanels: XULTabPanelsElement;
  tabs: XULTabsElement;
  template: XULElement;
  textnode: XULElement;
  textbox: XULTextBoxElement;
  titlebar: XULElement;
  toolbar: XULToolBarElement;
  toolbarbutton: XULToolBarButtonElement;
  toolbargrippy: XULToolBarGrippyElement;
  toolbaritem: XULToolBarItemElement;
  toolbarpalette: XULToolBarPaletteElement;
  toolbarseparator: XULToolBarSeparatorElement;
  toolbarset: XULToolBarSetElement;
  toolbarspacer: XULToolBarSpacerElement;
  toolbarspring: XULToolBarSpringElement;
  toolbox: XULToolBoxElement;
  tooltip: XULTooltipElement;
  tree: XULTreeElement;
  treecell: XULTreeCellElement;
  treechildren: XULTreeChildrenElement;
  treecol: XULTreeColElement;
  treecols: XULTreeColsElement;
  treeitem: XULTreeItemElement;
  treerow: XULTreeRowElement;
  treeseparator: XULTreeSeparatorElement;
  triple: XULElement;
  vbox: XULBoxElement;
  window: XULWindowElement;
  wizard: XULElement;
  wizardpage: XULElement;
}
//#endregion
//#region src/helpers/dialog.d.ts
/**
 * Dialog window helper. A superset of XUL dialog.
 */
declare class DialogHelper extends UITool {
  /**
   * Passed to dialog window for data-binding and lifecycle controls. See {@link DialogHelper.setDialogData}
   */
  dialogData: DialogData;
  /**
   * Dialog window instance
   */
  window: Window;
  protected elementProps: ElementProps & {
    tag: string;
  };
  /**
   * Create a dialog helper with row \* column grids.
   * @param row
   * @param column
   */
  constructor(row: number, column: number);
  /**
   * Add a cell at (row, column). Index starts from 0.
   * @param row
   * @param column
   * @param elementProps Cell element props. See {@link ElementProps}
   * @param cellFlex If the cell is flex. Default true.
   */
  addCell(row: number, column: number, elementProps: TagElementProps, cellFlex?: boolean): this;
  /**
   * Add a control button to the bottom of the dialog.
   * @param label Button label
   * @param id Button id.
   * The corresponding id of the last button user clicks before window exit will be set to `dialogData._lastButtonId`.
   * @param options Options
   * @param [options.noClose] Don't close window when clicking this button.
   * @param [options.callback] Callback of button click event.
   */
  addButton(label: string, id?: string, options?: {
    noClose?: boolean;
    callback?: (ev: Event) => any;
  }): this;
  /**
   * Dialog data.
   * @remarks
   * This object is passed to the dialog window.
   *
   * The control button id is in `dialogData._lastButtonId`;
   *
   * The data-binding values are in `dialogData`.
   * ```ts
   * interface DialogData {
   *   [key: string | number | symbol]: any;
   *   loadLock?: { promise: Promise<void>; resolve: () => void; isResolved: () => boolean }; // resolve after window load (auto-generated)
   *   loadCallback?: Function; // called after window load
   *   unloadLock?: { promise: Promise<void>; resolve: () => void }; // resolve after window unload (auto-generated)
   *   unloadCallback?: Function; // called after window unload
   *   beforeUnloadCallback?: Function; // called before window unload when elements are accessable.
   * }
   * ```
   * @param dialogData
   */
  setDialogData(dialogData: DialogData): this;
  /**
   * Open the dialog
   * @param title Window title
   * @param windowFeatures
   * @param windowFeatures.width Ignored if fitContent is `true`.
   * @param windowFeatures.height Ignored if fitContent is `true`.
   * @param windowFeatures.left
   * @param windowFeatures.top
   * @param windowFeatures.centerscreen Open window at the center of screen.
   * @param windowFeatures.resizable If window is resizable.
   * @param windowFeatures.fitContent Resize the window to content size after elements are loaded.
   * @param windowFeatures.noDialogMode Dialog mode window only has a close button. Set `true` to make maximize and minimize button visible.
   * @param windowFeatures.alwaysRaised Is the window always at the top.
   */
  open(title: string, windowFeatures?: {
    width?: number;
    height?: number;
    left?: number;
    top?: number;
    centerscreen?: boolean;
    resizable?: boolean;
    fitContent?: boolean;
    noDialogMode?: boolean;
    alwaysRaised?: boolean;
  }): this;
}
interface DialogData {
  [key: string | number | symbol]: any;
  loadLock?: {
    promise: Promise<void>;
    resolve: () => void;
    isResolved: () => boolean;
  };
  loadCallback?: () => void;
  unloadLock?: {
    promise: Promise<void>;
    resolve: () => void;
  };
  unloadCallback?: () => void;
  beforeUnloadCallback?: () => void;
  l10nFiles?: string | string[];
}
//#endregion
//#region src/helpers/filePicker.d.ts
/**
 * File picker helper.
 * @param title window title
 * @param mode
 * @param filters Array<[hint string, filter string]>
 * @param suggestion default file/folder
 * @param window the parent window. By default it is the main window
 * @param filterMask built-in filters
 * @param directory directory in which to open the file picker
 * @example
 * ```ts
 * await new FilePickerHelper(
 *   `${Zotero.getString("fileInterface.import")} MarkDown Document`,
 *   "open",
 *   [["MarkDown File(*.md)", "*.md"]]
 * ).open();
 * ```
 */
declare class FilePickerHelper<MODE extends "open" | "save" | "folder" | "multiple"> extends BasicTool {
  private title;
  private mode;
  private filters?;
  private suggestion?;
  private directory?;
  private window?;
  private filterMask?;
  constructor(title: string, mode: MODE, filters?: [string, string][], suggestion?: string, window?: Window, filterMask?: "all" | "html" | "text" | "images" | "xml" | "apps" | "urls" | "audio" | "video", directory?: string);
  open(): Promise<(MODE extends "multiple" ? string[] : string) | false>;
  private getMode;
  private getFilterMask;
}
//#endregion
//#region src/helpers/guide.d.ts
/**
 * Helper for creating a guide.
 * Designed for creating a step-by-step guide for users.
 * @alpha
 */
declare class GuideHelper extends BasicTool {
  _steps: GuideStep[];
  constructor();
  addStep(step: GuideStep): this;
  addSteps(steps: GuideStep[]): this;
  show(doc: Document): Promise<Guide>;
  highlight(doc: Document, step: GuideStep): Promise<Guide>;
}
interface GuideStep {
  element?: string | Element | (() => Element);
  title?: string;
  description?: string;
  position?: "before_start" | "before_end" | "after_start" | "after_end" | "start_before" | "start_after" | "end_before" | "end_after" | "overlap" | "after_pointer" | "center";
  showButtons?: ("next" | "prev" | "close")[];
  showProgress?: boolean;
  disableButtons?: ("next" | "prev" | "close")[];
  progressText?: string;
  closeBtnText?: string;
  nextBtnText?: string;
  prevBtnText?: string;
  onBeforeRender?: GuideHook;
  onRender?: GuideHook;
  onExit?: GuideHook;
  onNextClick?: GuideHook;
  onPrevClick?: GuideHook;
  onCloseClick?: GuideHook;
  onMask?: (props: {
    mask: (elem: Element) => void;
  }) => void;
}
type GuideHook = ({
  config,
  state
}: {
  config: GuideStep;
  state: GuideState;
}) => any;
interface GuideState {
  step: number;
  steps: GuideStep[];
  controller: Guide;
}
declare class Guide {
  _window: Window;
  _id: string;
  _panel: XULPopupElement;
  _header: HTMLDivElement;
  _body: HTMLDivElement;
  _footer: HTMLDivElement;
  _progress: HTMLDivElement;
  _closeButton: XUL.Button;
  _prevButton: XUL.Button;
  _nextButton: XUL.Button;
  _steps?: GuideStep[];
  _noClose: boolean;
  _closed: boolean;
  _autoNext: boolean;
  _currentIndex: number;
  initialized: boolean;
  _cachedMasks: WeakRef<HTMLElement | SVGElement>[];
  get content(): any;
  get currentStep(): GuideStep | undefined;
  get currentTarget(): Element | undefined;
  get hasNext(): boolean | undefined;
  get hasPrevious(): boolean | undefined;
  get hookProps(): Parameters<GuideHook>[0];
  get panel(): XULPopupElement;
  constructor(win: Window);
  show(steps?: GuideStep[]): Promise<void>;
  hide(): void;
  abort(): void;
  moveTo(stepIndex: number): void;
  moveNext(): void;
  movePrevious(): void;
  _handleShown(): void;
  _handleHidden(): Promise<void>;
  _centerPanel: () => void;
  _createMask(targetElement?: Element): void;
  _removeMask(): void;
}
//#endregion
//#region src/helpers/largePref.d.ts
/**
 * Helper class for storing large amounts of data in Zotero preferences.
 *
 * @remarks
 * The allowed data length for a single preference is at least 100k,
 * but if this can grow infinitely, like an Array or an Object,
 * there will be significant performance problems.
 *
 * This class stores the keys of data in a single preference as a JSON string of Array,
 * and stores the values of data in separate preferences.
 *
 * You can either use the class as a normal object with `asObject()`,
 * or use the methods to access the data.
 */
declare class LargePrefHelper extends BasicTool {
  private keyPref;
  private valuePrefPrefix;
  private innerObj;
  private hooks;
  /**
   *
   * @param keyPref The preference name for storing the keys of the data.
   * @param valuePrefPrefix The preference name prefix for storing the values of the data.
   * @param hooks Hooks for parsing the values of the data.
   * - `afterGetValue`: A function that takes the value of the data as input and returns the parsed value.
   * - `beforeSetValue`: A function that takes the key and value of the data as input and returns the parsed key and value.
   * If `hooks` is `"default"`, no parsing will be done.
   * If `hooks` is `"parser"`, the values will be parsed as JSON.
   * If `hooks` is an object, the values will be parsed by the hooks.
   */
  constructor(keyPref: string, valuePrefPrefix: string, hooks?: Partial<typeof defaultHooks> | "default" | "parser");
  /**
   * Get the object that stores the data.
   * @returns The object that stores the data.
   */
  asObject(): ProxyObj;
  /**
   * Get the Map that stores the data.
   * @returns The Map that stores the data.
   */
  asMapLike(): Map<string, any>;
  /**
   * Get the keys of the data.
   * @returns The keys of the data.
   */
  getKeys(): string[];
  /**
   * Set the keys of the data.
   * @param keys The keys of the data.
   */
  setKeys(keys: string[]): void;
  /**
   * Get the value of a key.
   * @param key The key of the data.
   * @returns The value of the key.
   */
  getValue(key: string): any;
  /**
   * Set the value of a key.
   * @param key The key of the data.
   * @param value The value of the key.
   */
  setValue(key: string, value: any): void;
  /**
   * Check if a key exists.
   * @param key The key of the data.
   * @returns Whether the key exists.
   */
  hasKey(key: string): boolean;
  /**
   * Add a key.
   * @param key The key of the data.
   */
  setKey(key: string): void;
  /**
   * Delete a key.
   * @param key The key of the data.
   */
  deleteKey(key: string): boolean;
  private constructTempObj;
  private constructTempMap;
}
type ProxyObj = Record<string | number, string | number | boolean>;
declare const defaultHooks: {
  afterGetValue: ({
    value
  }: {
    value: string;
  }) => {
    value: any;
  };
  beforeSetValue: ({
    key,
    value
  }: {
    key: string;
    value: any;
  }) => {
    key: string;
    value: any;
  };
};
//#endregion
//#region src/helpers/message.d.ts
type MessageParams<T extends MessageHandlers> = { [K in keyof T]: T[K] extends ((...params: infer P) => void) ? P : never };
type MessageReturnType<T extends MessageHandlers> = { [K in keyof T]: T[K] extends ((...params: any) => infer R) ? R : never };
interface MessageHandlers {
  [key: string]: (...data: any[]) => Promise<any> | any;
}
type PromisedMessageHandlers<T extends MessageHandlers> = { [K in keyof T]: (...data: Parameters<T[K]>) => Promise<Awaited<ReturnType<T[K]>>> };
interface MessageServerConfig {
  name: string;
  handlers: MessageHandlers;
  target?: Window | Worker;
  dev?: boolean;
  canBeDestroyed?: boolean;
}
interface BuiltInMessageHandlers {
  _start: () => Promise<void>;
  _stop: () => Promise<void>;
  _destroy: () => Promise<void>;
  _ping: () => Promise<void>;
  _call: (data: {
    func: string;
    args: any[];
  }) => Promise<any>;
  _get: (data: {
    key: string;
  }) => Promise<any>;
  _set: (data: {
    key: string;
    value: any;
  }) => Promise<void>;
}
/**
 * Helper class to manage messages between workers/iframes and their parent
 * @beta
 *
 * @example
 * Use the `MessageHelper` to create a server that can be used to communicate between workers or iframes and their parent.
 *
 * In the child `worker.js`:
 * ```typescript
 * const handlers = {
 *   async test() {
 *     return "test";
 *   },
 * };
 * // Create a new server
 * const server = new MessageHelper({
 *   name: "child",
 *   handlers,
 *   canBeDestroyed: true,
 * });
 * // Start the listener
 * server.start();
 * // Export the handlers for type hinting
 * export { handlers };
 * ```
 * In the parent:
 * ```typescript
 * // Import the handlers
 * import type { handlers } from "./worker.js";
 * // Create a new worker
 * const worker = new Worker("worker.js");
 * // Create a new server with the type from the target handlers
 * const server = new MessageHelper<typeof handlers>({
 *   name: "worker",
 *   handlers: {
 *     async test() {
 *       return "test";
 *     },
 *   },
 *   target: worker,
 * });
 * server.start();
 * // Execute the handlers defined in the worker as if they were local
 * ztoolkit.log(await server.proxy.test());
 * // ...
 * // Stop the server, can be restarted with server.start()
 * server.stop();
 * // Destroy the server and the worker
 * server.destroy();
 * ```
 *
 * @example
 * Evaluate code in the other side of the server
 * ```typescript
 * await server.eval("self.firstName = 'John';");
 * ```
 *
 * @example
 * Get a property from the other side of the server, can be nested.
 *
 * Only works if the property is a primitive or a serializable object
 * ```typescript
 * ztoolkit.log(await server.get("self.firstName"));
 * ```
 *
 * @example
 * Set a property from the other side of the server, can be nested.
 *
 * Only works if the property is a primitive or a serializable object
 * ```typescript
 * await server.set("self.firstName", "Alice");
 * ```
 *
 * @example
 * Check if the target is alive
 * ```typescript
 * ztoolkit.log(await server.isTargetAlive());
 * // Alternatively, send a ping message
 * ztoolkit.log(await server.proxy._ping());
 * ```
 */
declare class MessageHelper<_TargetHandlers extends MessageHandlers> {
  protected config: Required<MessageServerConfig>;
  protected env: "webworker" | "chromeworker" | "browser" | "content";
  protected listener?: any;
  running: boolean;
  /**
   * Proxy object to call the message handlers
   */
  proxy: PromisedMessageHandlers<_TargetHandlers & BuiltInMessageHandlers>;
  get target(): Window | Worker;
  get privileged(): boolean;
  constructor(config: MessageServerConfig);
  start(): void;
  stop(): void;
  destroy(): void;
  exec<_HandlersName extends keyof MessageParams<_HandlersType>, _HandlersType extends _TargetHandlers & BuiltInMessageHandlers>(name: _HandlersName, params?: MessageParams<_HandlersType>[_HandlersName], options?: {
    timeout?: number;
  }): Promise<Awaited<MessageReturnType<_HandlersType>[_HandlersName]>>;
  call(func: string, args: any[]): Promise<MessageReturnType<_TargetHandlers & BuiltInMessageHandlers>["_call"]>;
  get(key: string): Promise<MessageReturnType<_TargetHandlers & BuiltInMessageHandlers>["_get"]>;
  set(key: string, value: any): Promise<MessageReturnType<_TargetHandlers & BuiltInMessageHandlers>["_set"]>;
  eval(code: string): Promise<MessageReturnType<_TargetHandlers & BuiltInMessageHandlers>["_eval"]>;
  send(options: {
    name: string;
    data: any;
    jobID?: string;
    success?: boolean;
    requestReturn?: boolean;
  }): Promise<string>;
  isTargetAlive(): Promise<boolean>;
}
//#endregion
//#region src/helpers/patch.d.ts
declare class PatchHelper extends BasicTool {
  private options?;
  constructor();
  setData<T, K extends FunctionNamesOf<T>>(options: PatchOptions<T, K>): this;
  enable(): this;
  disable(): this;
}
declare interface PatchOptions<T, K extends FunctionNamesOf<T>> {
  target: T;
  funcSign: K;
  patcher: (origin: T[K]) => T[K];
  enabled: boolean;
}
//#endregion
//#region src/helpers/progressWindow.d.ts
/**
 * ProgressWindow helper.
 * @example
 * Show a popup with success icon
 * ```ts
 * const tool = new ZoteroTool();
 * tool.createProgressWindow("Addon").createLine({
 *   type: "success",
 *   text: "Finish"
 *   progress: 100,
 * }).show();
 * ```
 * @example
 * Show a popup and change line content
 * ```ts
 * const compat = new ZoteroCompat();
 * const tool = new ZoteroTool();
 * const popupWin = tool.createProgressWindow("Addon").createLine({
 *   text: "Loading"
 *   progress: 50,
 * }).show(-1);
 * // Do operations
 * compat.getGlobal("setTimeout")(()=>{
 *   popupWin.changeLine({
 *     text: "Finish",
 *     progress: 100,
 *   });
 * }, 3000);
 * ```
 */
declare class ProgressWindowHelper {
  win: Zotero.ProgressWindow;
  private lines;
  private closeTime;
  /**
   *
   * @param header window header
   * @param options
   * @param options.window
   * @param options.closeOnClick
   * @param options.closeTime
   * @param options.closeOtherProgressWindows
   */
  constructor(header: string, options?: {
    window?: Window;
    closeOnClick?: boolean;
    closeTime?: number;
    closeOtherProgressWindows?: boolean;
  });
  /**
   * Create a new line
   * @param options
   * @param options.type
   * @param options.icon
   * @param options.text
   * @param options.progress
   * @param options.idx
   */
  createLine(options: {
    type?: string;
    icon?: string;
    text?: string;
    progress?: number;
    idx?: number;
  }): this;
  /**
   * Change the line content
   * @param options
   * @param options.type
   * @param options.icon
   * @param options.text
   * @param options.progress
   * @param options.idx
   */
  changeLine(options: {
    type?: string;
    icon?: string;
    text?: string;
    progress?: number;
    idx?: number;
  }): this;
  show(closeTime?: number | undefined): this;
  /**
   * Set custom icon uri for progress window
   * @param key
   * @param uri
   */
  static setIconURI(key: string, uri: string): void;
  private getIcon;
  private updateIcons;
  changeHeadline(text: string, icon?: string, postText?: string): this;
  addLines(labels: string | {
    [key: string | number | symbol]: string;
  }, icons: string | {
    [key: string | number | symbol]: string;
  }): this;
  addDescription(text: string): this;
  startCloseTimer(ms: number, requireMouseOver?: boolean): this;
  close(): this;
}
//#endregion
//#region src/helpers/settingsDialog.d.ts
/**
 * Settings dialog helper. Extends DialogHelper with setting management capabilities.
 */
declare class SettingsDialogHelper extends DialogHelper {
  private settingsHandlers;
  private autoSaveButtonIds;
  private settingBindings;
  /**
   * Create a settings dialog helper.
   * Uses a 2-column grid layout by default (label column + control column)
   */
  constructor();
  /**
   * Set the setting handlers for getting and setting values.
   * @param getSetting Function to get a setting value by key
   * @param setSetting Function to set a setting value by key
   */
  setSettingHandlers(getSetting: (key: string) => any, setSetting: (key: string, value: any) => void): this;
  /**
   * Add a setting row with label and form control.
   * @param label Label text for the setting
   * @param settingKey The key used to store/retrieve the setting
   * @param controlProps Properties for the form control element
   * @param options Additional options
   * @param options.valueType Type of the setting value for proper conversion
   * @param options.labelProps Properties for the label element
   * @param options.condition Optional condition function to determine if the setting should be added
   *                          (returns true to add, false to skip)
   * @returns The SettingsDialogHelper instance for chaining
   */
  addSetting(label: string, settingKey: string, controlProps: TagElementProps, options?: {
    valueType?: "string" | "number" | "boolean";
    labelProps?: Partial<TagElementProps>;
    condition?: () => boolean;
  }): this;
  /**
   * Add a static row (label + static element) to the settings grid. This is not a form control.
   * @param label Label text for the row
   * @param staticElementProps Properties for the static element (e.g., text, icon, etc.)
   * @param options Additional options
   * @param options.labelProps Properties for the label element
   * @param options.condition Optional condition function to determine if the row should be added
   * @returns The SettingsDialogHelper instance for chaining
   */
  addStaticRow(label: string, staticElementProps: TagElementProps, options?: {
    labelProps?: Partial<TagElementProps>;
    condition?: () => boolean;
  }): this;
  /**
   * Add a control button that will auto-save settings when clicked.
   * @param label Button label
   * @param id Button id
   * @param options Button options
   * @param options.noClose Don't close window when clicking this button
   * @param options.validate Validation function for settings data
   * @param options.callback Callback of button click event
   */
  addAutoSaveButton(label: string, id?: string, options?: {
    noClose?: boolean;
    validate?: (data: any) => Promise<true | string> | true | string;
    callback?: (ev: Event) => any;
  }): this;
  /**
   * Save all settings using the setting handlers.
   */
  saveAllSettings(): void;
  /**
   * Collect and return all current setting values from the dialog controls.
   */
  getAllSettingsData(): Record<string, any>;
  /**
   * Load all settings from the setting handlers.
   */
  loadAllSettings(): void;
  /**
   * Override the open method to handle setting loading after window opens.
   */
  open(title: string, windowFeatures?: {
    width?: number;
    height?: number;
    left?: number;
    top?: number;
    centerscreen?: boolean;
    resizable?: boolean;
    fitContent?: boolean;
    noDialogMode?: boolean;
    alwaysRaised?: boolean;
  }): this;
  /**
   * Set control value based on element type and value type.
   */
  private setControlValue;
  /**
   * Set control value on an actual DOM element.
   */
  private setControlValueOnElement;
  /**
   * Get control value from a DOM element with proper type conversion.
   */
  private getControlValue;
}
//#endregion
//#region src/helpers/virtualizedTable.d.ts
/**
 * VirtualizedTable helper.
 */
declare class VirtualizedTableHelper extends BasicTool {
  props: VirtualizedTableProps;
  localeStrings: {
    [name: string]: string;
  };
  containerId: string;
  treeInstance: VirtualizedTable;
  private window;
  private React;
  private ReactDOM;
  private VirtualizedTable;
  private IntlProvider;
  constructor(win: Window);
  /**
   * Set properties by name.
   * @remarks
   * `id` and `getRowCount` are required.
   * If `id` is not set, it's a random string.
   * @param propName Property name
   * @param propValue Property value
   */
  setProp<K extends keyof VirtualizedTableProps, V extends VirtualizedTableProps[K]>(propName: K, propValue: V): VirtualizedTableHelper;
  /**
   * Set properties object.
   * @remarks
   * `id` and `getRowCount` are required.
   * If `id` is not set, it's a random string.
   * @param data property object.
   * @remarks
   * All available properties:
   * ```ts
   * interface VirtualizedTableProps {
   *   id: string;
   *   getRowCount: () => number;
   *   getRowData?: (index: number) => { [dataKey: string]: string };
   *   // Use `getRowData` instead. This property is generated automatically.
   *   renderItem?: (
   *     index: number,
   *     selection: TreeSelection,
   *     oldElem: HTMLElement,
   *     columns: ColumnOptions[]
   *   ) => Node;
   *   // Row height specified as lines of text per row. Defaults to 1
   *   linesPerRow?: number;
   *   // Do not adjust for Zotero-defined font scaling
   *   disableFontSizeScaling?: boolean;
   *   // An array of two elements for alternating row colors
   *   alternatingRowColors?: Array<string>;
   *   // For screen-readers
   *   label?: string;
   *   role?: string;
   *   showHeader?: boolean;
   *   // Array of column objects like the ones in itemTreeColumns.js
   *   columns?: Array<ColumnOptions>;
   *   onColumnPickerMenu?: (event: Event) => void;
   *   onColumnSort?: (columnIndex: number, ascending: 1 | -1) => void;
   *   getColumnPrefs?: () => { [dataKey: string]: any };
   *   storeColumnPrefs?: (prefs: { [dataKey: string]: any }) => void;
   *   getDefaultColumnOrder?: () => { [dataKey: string]: any };
   *   // Makes columns unmovable, unsortable, etc
   *   staticColumns?: boolean;
   *   // Used for initial column widths calculation
   *   containerWidth?: number;
   *   // Internal windowed-list ref
   *   treeboxRef?: (innerWindowedList: WindowedList) => any;
   *   // Render with display?: none
   *   hide?: boolean;
   *   multiSelect?: boolean;
   *   onSelectionChange?: (
   *     selection: TreeSelection,
   *     shouldDebounce: boolean
   *   ) => void;
   *   // The below are for arrow-key navigation
   *   isSelectable?: (index: number) => boolean;
   *   getParentIndex?: (index: number) => number;
   *   isContainer?: (index: number) => boolean;
   *   isContainerEmpty?: (index: number) => boolean;
   *   isContainerOpen?: (index: number) => boolean;
   *   toggleOpenState?: (index: number) => void;
   *   // A function with signature (index?:Number) => result?:String which will be used
   *   // for find-as-you-type navigation. Find-as-you-type is disabled if prop is undefined.
   *   getRowString?: (index: number) => string;
   *   // If you want to perform custom key handling it should be in this function
   *   // if it returns false then virtualized-table's own key handler won't run
   *   onKeyDown?: (e: Event) => boolean;
   *   onKeyUp?: (e: Event) => boolean;
   *   onDragOver?: (e: Event) => boolean;
   *   onDrop?: (e: Event) => boolean;
   *   // Enter, double-clicking
   *   onActivate?: (e: Event) => boolean;
   *   onFocus?: (e: Event) => boolean;
   *   onItemContextMenu?: (e: Event, x: number, y: number) => boolean;
   * }
   * ```
   */
  setProp(data: Partial<VirtualizedTableProps>): VirtualizedTableHelper;
  /**
   * Set locale strings, which replaces the table header's label if matches. Default it's `Zotero.Intl.strings`
   * @param localeStrings
   */
  setLocale(localeStrings: {
    [name: string]: string;
  }): this;
  /**
   * Set container element id that the table will be rendered on.
   * @param id element id
   */
  setContainerId(id: string): this;
  /**
   * Render the table.
   * @param selectId Which row to select after rendering
   * @param onfulfilled callback after successfully rendered
   * @param onrejected callback after rendering with error
   */
  render(selectId?: number, onfulfilled?: (value: unknown) => unknown, onrejected?: (reason: any) => PromiseLike<never>): this;
}
interface ColumnOptions {
  dataKey: string;
  label: string;
  iconLabel?: React.ReactElement;
  defaultSort?: 1 | -1;
  flex?: number;
  width?: number;
  fixedWidth?: boolean;
  staticWidth?: boolean;
  minWidth?: number;
  ignoreInColumnPicker?: boolean;
  submenu?: boolean;
}
interface VirtualizedTableProps {
  id: string;
  getRowCount: () => number;
  getRowData?: (index: number) => {
    [dataKey: string]: string;
  };
  /**
   * Use `getRowData` instead. This property is generated automatically.
   * @param index
   * @param selection
   * @param oldElem
   * @param columns
   */
  renderItem?: (index: number, selection: TreeSelection, oldElem: HTMLElement, columns: ColumnOptions[]) => Node;
  linesPerRow?: number;
  disableFontSizeScaling?: boolean;
  alternatingRowColors?: Array<string>;
  label?: string;
  role?: string;
  showHeader?: boolean;
  columns?: Array<ColumnOptions>;
  onColumnPickerMenu?: (event: Event) => void;
  onColumnSort?: (columnIndex: number, ascending: 1 | -1) => void;
  getColumnPrefs?: () => {
    [dataKey: string]: any;
  };
  storeColumnPrefs?: (prefs: {
    [dataKey: string]: any;
  }) => void;
  getDefaultColumnOrder?: () => {
    [dataKey: string]: any;
  };
  staticColumns?: boolean;
  containerWidth?: number;
  treeboxRef?: (innerWindowedList: WindowedList) => any;
  hide?: boolean;
  multiSelect?: boolean;
  onSelectionChange?: (selection: TreeSelection, shouldDebounce: boolean) => void;
  isSelectable?: (index: number) => boolean;
  getParentIndex?: (index: number) => number;
  isContainer?: (index: number) => boolean;
  isContainerEmpty?: (index: number) => boolean;
  isContainerOpen?: (index: number) => boolean;
  toggleOpenState?: (index: number) => void;
  getRowString?: (index: number) => string;
  onKeyDown?: (e: KeyboardEvent) => boolean;
  onKeyUp?: (e: KeyboardEvent) => boolean;
  onDragOver?: (e: DragEvent) => boolean;
  onDrop?: (e: DragEvent) => boolean;
  onActivate?: (e: MouseEvent) => boolean;
  onFocus?: (e: FocusEvent) => boolean;
  onItemContextMenu?: (e: MouseEvent | KeyboardEvent, x: number, y: number) => boolean;
}
interface VirtualizedTable extends React.Component<VirtualizedTableProps, object> {
  selection: TreeSelection;
  invalidate: () => void;
}
/**
 * Somewhat corresponds to nsITreeSelection
 * https://udn.realityripple.com/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsITreeSelection
 *
 * @property pivot {Number} The selection "pivot". This is the first item the user selected as part of
 * 		a ranged select (i.e. shift-select).
 * @property focused {Number} The currently selected/focused item.
 * @property count {Number} The number of selected items
 * @property selected {Set} The set of currently selected items
 * @property selectEventsSuppressed {Boolean} Controls whether select events are triggered on selection change.
 */
interface TreeSelection {
  _tree: VirtualizedTable;
  pivot: number;
  focused: number;
  selected: Set<number>;
  _selectEventsSuppressed: boolean;
  /**
   * @param tree {VirtualizedTable} The tree where selection occurs. Will be used to issue
   * updates.
   */
  new (tree: VirtualizedTable): this;
  /**
   * Returns whether the given index is selected.
   * @param index {Number} The index is 0-clamped.
   * @returns {boolean}
   */
  isSelected: (index: number) => boolean;
  /**
   * Toggles an item's selection state, updates focused item to index.
   * @param index {Number} The index is 0-clamped.
   * @param shouldDebounce {Boolean} Whether the update to the tree should be debounced
   */
  toggleSelect: (index: number, shouldDebounce?: boolean) => void;
  clearSelection: () => void;
  /**
   * Selects an item, updates focused item to index.
   * @param index {Number} The index is 0-clamped.
   * @param shouldDebounce {Boolean} Whether the update to the tree should be debounced
   * @returns {boolean} False if nothing to select and select handlers won't be called
   */
  select: (index: number, shouldDebounce?: boolean) => boolean;
  rangedSelect: (from: number, to: number, augment: boolean, isSelectAll: boolean) => void;
  /**
   * Performs a shift-select from current pivot to provided index. Updates focused item to index.
   * @param index {Number} The index is 0-clamped.
   * @param augment {Boolean} Adds to existing selection if true
   * @param shouldDebounce {Boolean} Whether the update to the tree should be debounced
   */
  shiftSelect: (index: number, augment: boolean, shouldDebounce?: boolean) => void;
  /**
   * Calls the onSelectionChange prop on the tree
   * @param shouldDebounce {Boolean} Whether the update to the tree should be debounced
   * @private
   */
  _updateTree: (shouldDebounce?: boolean) => void;
  get count(): number;
  get selectEventsSuppressed(): boolean;
  set selectEventsSuppressed(val: boolean);
}
interface WindowedList {
  [key: string | number | symbol]: any;
}
//#endregion
//#region src/managers/fieldHook.d.ts
/**
 * Item field hooks manager.
 */
declare class FieldHookManager extends ManagerTool {
  private data;
  private patchHelpers;
  constructor(base?: BasicTool | BasicOptions);
  /**
   * Register `Zotero.Item.getField` hook.
   * @param type
   * @param field
   * @param hook ( field: string, unformatted: boolean, includeBaseMapped: boolean, item: Zotero.Item, original: Function) => string
   */
  register(type: "getField", field: string, hook: typeof getFieldHookFunc): void;
  /**
   * Register `Zotero.Item.setField` hook.
   * @param type
   * @param field
   * @param hook ( field: string, value: string, loadIn: boolean, item: Zotero.Item, original: Function) => void
   */
  register(type: "setField", field: string, hook: typeof setFieldHookFunc): void;
  /**
   * Register `Zotero.ItemFields.isFieldOfBase` hook. Used in itemBox.
   * @param type
   * @param field
   * @param hook ( field: string, baseField: string, original: Function) => void
   */
  register(type: "isFieldOfBase", field: string, hook: typeof isFieldOfBaseHookFunc): void;
  unregister(type: "getField" | "setField" | "isFieldOfBase", field: string): void;
  unregisterAll(): void;
}
declare function getFieldHookFunc(field: string, unformatted: boolean, includeBaseMapped: boolean, item: Zotero.Item, original: Function): string;
declare function setFieldHookFunc(field: string, value: string, loadIn: boolean, item: Zotero.Item, original: Function): boolean;
declare function isFieldOfBaseHookFunc(field: string, baseField: string | number, original: Function): boolean;
//#endregion
//#region src/managers/keyboard.d.ts
/**
 * Register a global keyboard event listener.
 */
declare class KeyboardManager extends ManagerTool {
  private _keyboardCallbacks;
  private _cachedKey?;
  private id;
  constructor(base?: BasicTool | BasicOptions);
  /**
   * Register a keyboard event listener.
   * @param callback The callback function.
   */
  register(callback: KeyboardCallback): void;
  /**
   * Unregister a keyboard event listener.
   * @param callback The callback function.
   */
  unregister(callback: KeyboardCallback): void;
  /**
   * Unregister all keyboard event listeners.
   */
  unregisterAll(): void;
  private initKeyboardListener;
  private unInitKeyboardListener;
  private initReaderKeyboardListener;
  private addReaderKeyboardCallback;
  private _initKeyboardListener;
  private _unInitKeyboardListener;
  private triggerKeydown;
  private triggerKeyup;
  private dispatchCallback;
}
type KeyboardEventType = "keydown" | "keyup";
type KeyboardCallback = (event: KeyboardEvent, options: {
  keyboard?: KeyModifier;
  type: KeyboardEventType;
}) => void;
interface KeyModifierStatus {
  accel: boolean;
  shift: boolean;
  control: boolean;
  meta: boolean;
  alt: boolean;
  key: string;
}
/**
 * Class to represent key with modifiers
 */
declare class KeyModifier implements KeyModifierStatus {
  accel: boolean;
  shift: boolean;
  control: boolean;
  meta: boolean;
  alt: boolean;
  key: string;
  useAccel: boolean;
  constructor(raw?: string | KeyboardEvent | KeyModifier, options?: {
    useAccel?: boolean;
  });
  /**
   * Merge another KeyModifier into this one.
   * @param newMod the new KeyModifier
   * @param options
   * @param options.allowOverwrite
   * @returns KeyModifier
   */
  merge(newMod: KeyModifier, options?: {
    allowOverwrite?: boolean;
  }): this;
  /**
   * Check if the current KeyModifier equals to another KeyModifier.
   * @param newMod the new KeyModifier
   * @returns true if equals
   */
  equals(newMod: KeyModifier | string): boolean;
  /**
   * Get the raw string representation of the KeyModifier.
   */
  getRaw(): string;
  /**
   * Get the localized string representation of the KeyModifier.
   */
  getLocalized(): string;
  /**
   * Get the un-localized string representation of the KeyModifier.
   */
  private unLocalized;
  private mergeAttribute;
}
//#endregion
//#region src/managers/menu.d.ts
/**
 * Register \<menuitem\>, \<menupopup\>, or \<menuseperator\> to Zotero right-click/window menus.
 */
declare class MenuManager extends ManagerTool {
  private ui;
  constructor(base?: BasicTool | BasicOptions);
  /**
   * Insert an menu item/menu(with popup)/menuseprator into a menupopup
   * @remarks
   * options:
   * ```ts
   * export interface MenuitemOptions {
   *   tag: "menuitem" | "menu" | "menuseparator";
   *   id?: string;
   *   label?: string;
   *   // data url (chrome://xxx.png) or base64 url (data:image/png;base64,xxx)
   *   icon?: string;
   *   class?: string;
   *   styles?: { [key: string]: string };
   *   hidden?: boolean;
   *   disabled?: boolean;
   *   oncommand?: string;
   *   commandListener?: EventListenerOrEventListenerObject;
   *   // Attributes below are used when type === "menu"
   *   popupId?: string;
   *   onpopupshowing?: string;
   *   subElementOptions?: Array<MenuitemOptions>;
   * }
   * ```
   * @param menuPopup
   * @param options
   * @param insertPosition
   * @param anchorElement The menuitem will be put before/after `anchorElement`. If not set, put at start/end of the menupopup.
   * @example
   * Insert menuitem with icon into item menupopup
   * ```ts
   * // base64 or chrome:// url
   * const menuIcon = "chrome://addontemplate/content/icons/favicon@0.5x.png";
   * ztoolkit.Menu.register("item", {
   *   tag: "menuitem",
   *   id: "zotero-itemmenu-addontemplate-test",
   *   label: "Addon Template: Menuitem",
   *   oncommand: "alert('Hello World! Default Menuitem.')",
   *   icon: menuIcon,
   * });
   * ```
   * @example
   * Insert menu into file menupopup
   * ```ts
   * ztoolkit.Menu.register(
   *   "menuFile",
   *   {
   *     tag: "menu",
   *     label: "Addon Template: Menupopup",
   *     subElementOptions: [
   *       {
   *         tag: "menuitem",
   *         label: "Addon Template",
   *         oncommand: "alert('Hello World! Sub Menuitem.')",
   *       },
   *     ],
   *   },
   *   "before",
   *   Zotero.getMainWindow().document.querySelector(
   *     "#zotero-itemmenu-addontemplate-test"
   *   )
   * );
   * ```
   */
  register(menuPopup: XUL.MenuPopup | keyof typeof MenuSelector, options: MenuitemOptions, insertPosition?: "before" | "after", anchorElement?: XUL.Element): false | undefined;
  unregister(menuId: string): void;
  unregisterAll(): void;
}
declare enum MenuSelector {
  menuFile = "#menu_FilePopup",
  menuEdit = "#menu_EditPopup",
  menuView = "#menu_viewPopup",
  menuGo = "#menu_goPopup",
  menuTools = "#menu_ToolsPopup",
  menuHelp = "#menu_HelpPopup",
  collection = "#zotero-collectionmenu",
  item = "#zotero-itemmenu",
}
type MenuitemTagDependentOptions = {
  tag: "menuitem";
  /**
   * return true to show and false to hide current element
   * @deprecated Use `isHidden`.
   */
  getVisibility?: (elem: XUL.MenuItem, ev: Event) => boolean | undefined;
  /**
   * Dynamically hide/show the menu item
   * @returns Whether the menu item should be hidden
   */
  isHidden?: (elem: XUL.MenuItem, ev: Event) => boolean | undefined;
  /**
   * Dynamically enable/disable the menu item
   * @returns Whether the menu item should be disabled
   */
  isDisabled?: (elem: XUL.MenuItem, ev: Event) => boolean | undefined;
  /**
   * Fired when the containing menu popup is shown
   */
  onShowing?: (elem: XUL.MenuItem, event: Event) => any;
  type?: "" | "checkbox" | "radio";
  checked?: boolean;
} | {
  tag: "menu";
  /**
   * return true to show and false to hide current element
   * @deprecated Use `isHidden`.
   */
  getVisibility?: (elem: XUL.Menu, ev: Event) => boolean | undefined;
  /**
   * Dynamically hide/show the menu
   * @returns Whether the menu should be hidden
   */
  isHidden?: (elem: XUL.Menu, ev: Event) => boolean | undefined;
  /**
   * Dynamically enable/disable the menu
   * @returns Whether the menu should be disabled
   */
  isDisabled?: (elem: XUL.Menu, ev: Event) => boolean | undefined;
  popupId?: string;
  /**
   * Fired when the containing menu popup is shown. Consider using `onShowing` instead.
   */
  onpopupshowing?: string;
  children?: Array<MenuitemOptions>;
  /**
   * @deprecated Use `children`.
   */
  subElementOptions?: Array<MenuitemOptions>;
} | {
  tag: "menuseparator";
  /**
   * return true to show and false to hide current element
   * @deprecated Use `isHidden`.
   */
  getVisibility?: (elem: XUL.MenuSeparator, ev: Event) => boolean | undefined;
  /**
   * Dynamically hide/show the separator
   * @returns Whether the separator should be hidden
   */
  isHidden?: (elem: XUL.MenuSeparator, ev: Event) => boolean | undefined;
  /**
   * Dynamically enable/disable the separator
   * @returns Whether the separator should be disabled
   */
  isDisabled?: (elem: XUL.MenuSeparator, ev: Event) => boolean | undefined;
  /**
   * Fired when the containing menu popup is shown
   */
  onShowing?: (elem: XUL.MenuSeparator, event: Event) => any;
};
interface MenuitemCommonOptions {
  id?: string;
  label?: string;
  icon?: string;
  classList?: string[];
  class?: string;
  styles?: {
    [key: string]: string;
  };
  hidden?: boolean;
  disabled?: boolean;
  oncommand?: string;
  commandListener?: EventListenerOrEventListenerObject | ((event: Event) => any);
}
type MenuitemOptions = MenuitemTagDependentOptions & MenuitemCommonOptions;
//#endregion
//#region src/managers/toolkitGlobal.d.ts
interface GlobalInstance {
  _ready: boolean;
}
//#endregion
//#region src/managers/prompt.d.ts
/**
 * Prompt for setting up or executing some commands quickly.
 *
 * `Shift + P` can show/hide its UI anywhere after registering commands.
 */
declare class Prompt {
  private ui;
  private base;
  get document(): Document;
  /**
   * Record the last text entered
   */
  private lastInputText;
  /**
   * Default text
   */
  private defaultText;
  /**
   * It controls the max line number of commands displayed in `commandsNode`.
   */
  private maxLineNum;
  /**
   * It controls the max number of suggestions.
   */
  private maxSuggestionNum;
  /**
   * The top-level HTML div node of `Prompt`
   */
  promptNode: HTMLDivElement;
  /**
   * The HTML input node of `Prompt`.
   */
  inputNode: HTMLInputElement;
  /**
   * Save all commands registered by all addons.
   */
  commands: Command[];
  /**
   * Initialize `Prompt` but do not create UI.
   */
  constructor();
  /**
   * Initialize `Prompt` UI and then bind events on it.
   */
  initializeUI(): void;
  private createHTML;
  /**
   * Show commands in a new `commandsContainer`
   * All other `commandsContainer` is hidden
   * @param commands Command[]
   * @param clear remove all `commandsContainer` if true
   */
  showCommands(commands: Command[], clear?: boolean): void;
  /**
   * Create a `commandsContainer` div element, append to `commandsContainer` and hide others.
   * @returns commandsNode
   */
  createCommandsContainer(): HTMLDivElement;
  /**
   * Return current displayed `commandsContainer`
   * @returns
   */
  private getCommandsContainer;
  /**
   * Create a command item for `Prompt` UI.
   * @param command
   * @returns
   */
  createCommandNode(command: Command): HTMLElement;
  /**
   * Called when `enter` key is pressed.
   */
  private trigger;
  /**
   * Called when `escape` key is pressed.
   */
  private exit;
  private execCallback;
  /**
   * Match suggestions for user's entered text.
   */
  private showSuggestions;
  /**
   * Bind events of pressing `keydown` and `keyup` key.
   */
  private initInputEvents;
  /**
   * Create a commandsContainer and display a text
   */
  showTip(text: string): HTMLDivElement;
  /**
   * Mark the selected item with class `selected`.
   * @param item HTMLDivElement
   */
  selectItem(item: HTMLDivElement): void;
  private addStyle;
  private registerShortcut;
}
declare class PromptManager extends ManagerTool {
  prompt: Prompt;
  /**
   * Save the commands registered from this manager
   */
  private commands;
  constructor(base?: BasicTool | BasicOptions);
  /**
   * Register commands. Don't forget to call `unregister` on plugin exit.
   * @param commands Command[]
   * @example
   * ```ts
   * let getReader = () => {
   *   return BasicTool.getZotero().Reader.getByTabID(
   *     (Zotero.getMainWindow().Zotero_Tabs).selectedID
   *   )
   * }
   *
   * register([
   *   {
   *     name: "Split Horizontally",
   *     label: "Zotero",
   *     when: () => getReader() as boolean,
   *     callback: (prompt: Prompt) => getReader().menuCmd("splitHorizontally")
   *   },
   *   {
   *     name: "Split Vertically",
   *     label: "Zotero",
   *     when: () => getReader() as boolean,
   *     callback: (prompt: Prompt) => getReader().menuCmd("splitVertically")
   *   }
   * ])
   * ```
   */
  register(commands: {
    name?: string;
    label?: string;
    id?: string;
    when?: () => boolean;
    callback: ((prompt: Prompt) => Promise<void>) | ((prompt: Prompt) => void) | Command[];
  }[]): void;
  /**
   * You can delete a command registed before by its name.
   * @remarks
   * There is a premise here that the names of all commands registered by a single plugin are not duplicated.
   * @param id Command.name
   */
  unregister(id: string): void;
  /**
   * Call `unregisterAll` on plugin exit.
   */
  unregisterAll(): void;
}
interface Command {
  name?: string;
  label?: string;
  id?: string;
  when?: () => boolean;
  callback: ((prompt: Prompt) => Promise<void>) | ((prompt: Prompt) => void) | Command[];
}
interface PromptGlobal extends GlobalInstance {
  instance: Prompt | undefined;
}
//#endregion
//#region src/tools/extraField.d.ts
/**
 * Get/set extra field APIs.
 */
declare class ExtraFieldTool extends BasicTool {
  /**
   * Get all extra fields
   * @param item
   */
  getExtraFields(item: Zotero.Item, backend?: "default" | "custom"): Map<string, string>;
  /**
   * Get extra field value by key. If it does not exists, return undefined.
   * @param item
   * @param key
   */
  getExtraField(item: Zotero.Item, key: string): string | undefined;
  /**
   * Replace extra field of an item.
   * @param item
   * @param fields
   */
  replaceExtraFields(item: Zotero.Item, fields: Map<string, string>): Promise<void>;
  /**
   * Set an key-value pair to the item's extra field
   * @param item
   * @param key
   * @param value
   */
  setExtraField(item: Zotero.Item, key: string, value: string): Promise<void>;
}
//#endregion
//#region src/tools/reader.d.ts
/**
 * Zotero ReaderInstance APIs.
 */
declare class ReaderTool extends BasicTool {
  /**
   * Get the selected tab reader.
   * @param waitTime Wait for n MS until the reader is ready
   */
  getReader(waitTime?: number): Promise<_ZoteroTypes.ReaderInstance | undefined>;
  /**
   * Get all window readers.
   */
  getWindowReader(): Array<_ZoteroTypes.ReaderWindow>;
  /**
   * Get Reader tabpanel deck element.
   * @deprecated - use item pane api
   * @alpha
   */
  getReaderTabPanelDeck(): XUL.Deck;
  /**
   * Add a reader tabpanel deck selection change observer.
   * @deprecated - use item pane api
   * @alpha
   * @param callback
   */
  addReaderTabPanelDeckObserver(callback: () => void): Promise<MutationObserver>;
  /**
   * Get the selected annotation data.
   * @param reader Target reader
   * @returns The selected annotation data.
   */
  getSelectedAnnotationData(reader: _ZoteroTypes.ReaderInstance): AnnotationData | undefined;
  /**
   * Get the text selection of reader.
   * @param reader Target reader
   * @returns The text selection of reader.
   */
  getSelectedText(reader: _ZoteroTypes.ReaderInstance): string;
}
interface AnnotationData {
  color?: string;
  pageLabel: string;
  position: Record<string, any>;
  sortIndex: string;
  text: string;
  type: _ZoteroTypes.Annotations.AnnotationType;
}
declare namespace wait_d_exports {
  export { waitForReader, waitUntil, waitUntilAsync, waitUtilAsync };
}
declare function waitUntil(condition: () => boolean, callback: () => void, interval?: number, timeout?: number): void;
declare const waitUtilAsync: typeof waitUntilAsync;
declare function waitUntilAsync(condition: () => boolean, interval?: number, timeout?: number): Promise<void>;
declare function waitForReader(reader: _ZoteroTypes.ReaderInstance): Promise<void>;
//#endregion
//#region src/ztoolkit.d.ts
/**
 * ⭐Contains all tools in this lib. Start from here if you are new to this lib.
 * @remarks
 * To minimize your plugin, import the modules you need manually.
 */
declare class ZoteroToolkit extends BasicTool {
  static _version: string;
  UI: UITool;
  Reader: ReaderTool;
  ExtraField: ExtraFieldTool;
  FieldHooks: FieldHookManager;
  Keyboard: KeyboardManager;
  Prompt: PromptManager;
  Menu: MenuManager;
  Clipboard: typeof ClipboardHelper;
  FilePicker: typeof FilePickerHelper;
  Patch: typeof PatchHelper;
  ProgressWindow: typeof ProgressWindowHelper;
  VirtualizedTable: typeof VirtualizedTableHelper;
  Dialog: typeof DialogHelper;
  LargePrefObject: typeof LargePrefHelper;
  Guide: typeof GuideHelper;
  constructor();
  /**
   * Unregister everything created by managers.
   */
  unregisterAll(): void;
}
//#endregion
export { BasicOptions, BasicTool, ClipboardHelper, ColumnOptions, Command, DialogData, DialogHelper, ElementProps, ExtraFieldTool, FieldHookManager, FilePickerHelper, FragmentElementProps, GuideHelper, HTMLElementProps, KeyModifier, KeyboardManager, LargePrefHelper, ManagerTool, MenuManager, MenuitemOptions, MessageHelper, PatchHelper, ProgressWindowHelper, Prompt, PromptGlobal, PromptManager, ReaderTool, SettingsDialogHelper, TagElementProps, UIOptions, UITool, VirtualizedTableHelper, XULElementProps, ZoteroToolkit, _importESModule, getFieldHookFunc, isFieldOfBaseHookFunc, makeHelperTool, setFieldHookFunc, unregister, wait_d_exports as wait };