From fbfc7467b5a7796cfa01da09553ff7f4927eff30 Mon Sep 17 00:00:00 2001
From: frostime <frostime@foxmail.com>
Date: Sat, 3 Jun 2023 15:50:28 +0800
Subject: [PATCH] copy from `plugin-sample:index.ts`

---
 .gitignore      |   1 +
 plugin.json     |   2 +-
 src/index.ts    | 293 +++++++++++++++++++++++----------
 src/siyuan.d.ts | 424 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 630 insertions(+), 90 deletions(-)
 create mode 100644 src/siyuan.d.ts

diff --git a/.gitignore b/.gitignore
index aa00657..764e2d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ node_modules
 dev
 dist
 build
+tmp
diff --git a/plugin.json b/plugin.json
index 8558256..37acc2b 100644
--- a/plugin.json
+++ b/plugin.json
@@ -2,7 +2,7 @@
   "name": "plugin-sample-vite-svelte",
   "author": "frostime",
   "url": "https://github.com/siyuan-note/plugin-sample-vite-svelte",
-  "version": "0.0.6",
+  "version": "0.1.3",
   "minAppVersion": "2.9.0",
   "displayName": {
     "en_US": "Plugin sample with vite and svelte",
diff --git a/src/index.ts b/src/index.ts
index e2f27cd..7c129b5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,15 @@
-import { Plugin, showMessage, confirm, Dialog, Menu, isMobile, openTab, adaptHotkey } from "siyuan";
+import {
+    Plugin,
+    showMessage,
+    confirm,
+    Dialog,
+    Menu,
+    openTab,
+    adaptHotkey,
+    getFrontend,
+    getBackend,
+    IModel
+} from "siyuan";
 import "./index.scss";
 
 import HelloExample from "./hello.svelte";
@@ -11,20 +22,53 @@ const DOCK_TYPE = "dock_tab";
 export default class SamplePlugin extends Plugin {
 
     private customTab: () => any;
+    private isMobile: boolean;
 
     async onload() {
-        showMessage("Hello SiYuan Plugin");
-        this.data[STORAGE_NAME] = {readonlyText: "Readonly"};
+        this.data[STORAGE_NAME] = { readonlyText: "Readonly" };
+
+        const frontEnd = getFrontend();
+        this.isMobile = frontEnd === "mobile" || frontEnd === "browser-mobile";
+        // 图标的制作参见帮助文档
+        this.addIcons(`<symbol id="iconFace" viewBox="0 0 32 32">
+<path d="M13.667 17.333c0 0.92-0.747 1.667-1.667 1.667s-1.667-0.747-1.667-1.667 0.747-1.667 1.667-1.667 1.667 0.747 1.667 1.667zM20 15.667c-0.92 0-1.667 0.747-1.667 1.667s0.747 1.667 1.667 1.667 1.667-0.747 1.667-1.667-0.747-1.667-1.667-1.667zM29.333 16c0 7.36-5.973 13.333-13.333 13.333s-13.333-5.973-13.333-13.333 5.973-13.333 13.333-13.333 13.333 5.973 13.333 13.333zM14.213 5.493c1.867 3.093 5.253 5.173 9.12 5.173 0.613 0 1.213-0.067 1.787-0.16-1.867-3.093-5.253-5.173-9.12-5.173-0.613 0-1.213 0.067-1.787 0.16zM5.893 12.627c2.28-1.293 4.040-3.4 4.88-5.92-2.28 1.293-4.040 3.4-4.88 5.92zM26.667 16c0-1.040-0.16-2.040-0.44-2.987-0.933 0.2-1.893 0.32-2.893 0.32-4.173 0-7.893-1.92-10.347-4.92-1.4 3.413-4.187 6.093-7.653 7.4 0.013 0.053 0 0.12 0 0.187 0 5.88 4.787 10.667 10.667 10.667s10.667-4.787 10.667-10.667z"></path>
+</symbol>
+<symbol id="iconSaving" viewBox="0 0 32 32">
+<path d="M20 13.333c0-0.733 0.6-1.333 1.333-1.333s1.333 0.6 1.333 1.333c0 0.733-0.6 1.333-1.333 1.333s-1.333-0.6-1.333-1.333zM10.667 12h6.667v-2.667h-6.667v2.667zM29.333 10v9.293l-3.76 1.253-2.24 7.453h-7.333v-2.667h-2.667v2.667h-7.333c0 0-3.333-11.28-3.333-15.333s3.28-7.333 7.333-7.333h6.667c1.213-1.613 3.147-2.667 5.333-2.667 1.107 0 2 0.893 2 2 0 0.28-0.053 0.533-0.16 0.773-0.187 0.453-0.347 0.973-0.427 1.533l3.027 3.027h2.893zM26.667 12.667h-1.333l-4.667-4.667c0-0.867 0.12-1.72 0.347-2.547-1.293 0.333-2.347 1.293-2.787 2.547h-8.227c-2.573 0-4.667 2.093-4.667 4.667 0 2.507 1.627 8.867 2.68 12.667h2.653v-2.667h8v2.667h2.68l2.067-6.867 3.253-1.093v-4.707z"></path>
+</symbol>`);
 
         const topBarElement = this.addTopBar({
-            icon: "iconEmoji",
+            icon: "iconFace",
             title: this.i18n.addTopBarIcon,
-            position: "left",
+            position: "right",
             callback: () => {
-                this.addMenu(topBarElement.getBoundingClientRect());
+                let rect = topBarElement.getBoundingClientRect();
+                // 如果被隐藏,则使用更多按钮
+                if (rect.width === 0) {
+                    rect = document.querySelector("#barMore").getBoundingClientRect();
+                }
+                this.addMenu(rect);
             }
         });
 
+        const statusIconTemp = document.createElement("template");
+        statusIconTemp.innerHTML = `<div class="toolbar__item b3-tooltips b3-tooltips__w" aria-label="Remove plugin-sample Data">
+    <svg>
+        <use xlink:href="#iconTrashcan"></use>
+    </svg>
+</div>`;
+        statusIconTemp.content.firstElementChild.addEventListener("click", () => {
+            confirm("⚠️", this.i18n.confirmRemove.replace("${name}", this.name), () => {
+                this.removeData(STORAGE_NAME).then(() => {
+                    this.data[STORAGE_NAME] = { readonlyText: "Readonly" };
+                    showMessage(`[${this.name}]: ${this.i18n.removedData}`);
+                });
+            });
+        });
+        this.addStatusBar({
+            element: statusIconTemp.content.firstElementChild as HTMLElement,
+        });
+
         let div = document.createElement("div");
         new HelloExample({
             target: div,
@@ -44,10 +88,18 @@ export default class SamplePlugin extends Plugin {
             }
         });
 
+        this.addCommand({
+            langKey: "showDialog",
+            hotkey: "⇧⌘M",
+            callback: () => {
+                this.showDialog();
+            }
+        });
+
         this.addDock({
             config: {
                 position: "LeftBottom",
-                size: {width: 200, height: 0},
+                size: { width: 200, height: 0 },
                 icon: "iconEmoji",
                 title: "Custom Dock",
             },
@@ -79,6 +131,7 @@ export default class SamplePlugin extends Plugin {
 
     onLayoutReady() {
         this.loadData(STORAGE_NAME);
+        console.log(`frontend: ${getFrontend()}; backend: ${getBackend()}`);
     }
 
     onunload() {
@@ -87,11 +140,27 @@ export default class SamplePlugin extends Plugin {
         console.log("onunload");
     }
 
-    private wsEvent({ detail }: any) {
+    openSetting(): void {
+        let dialog = new Dialog({
+            title: "SettingPannel",
+            content: `<div id="SettingPanel"></div>`,
+            width: "600px",
+            destroyCallback: (options) => {
+                console.log("destroyCallback", options);
+                //You must destroy the component when the dialog is closed
+                pannel.$destroy();
+            }
+        });
+        let pannel = new SettingPannel({
+            target: dialog.element.querySelector("#SettingPanel"),
+        });
+    }
+
+    private eventBusLog({ detail }: any) {
         console.log(detail);
     }
 
-    private blockIconEvent({detail}: any) {
+    private blockIconEvent({ detail }: any) {
         console.log(detail);
         detail.menu.addSeparator(0);
         const ids: string[] = [];
@@ -106,70 +175,108 @@ export default class SamplePlugin extends Plugin {
         });
     }
 
-    private async addMenu(rect: DOMRect) {
+    private showDialog() {
+        new Dialog({
+            title: "Info",
+            content: '<div class="b3-dialog__content">This is a dialog</div>',
+            width: this.isMobile ? "92vw" : "520px",
+        });
+    }
+
+    private addMenu(rect: DOMRect) {
         const menu = new Menu("topBarSample", () => {
             console.log(this.i18n.byeMenu);
         });
-        menu.addItem({
-            icon: "iconHelp",
-            label: "Confirm",
-            click() {
-                confirm("Confirm", "Is this a confirm?", () => {
-                    showMessage("confirm");
-                }, () => {
-                    showMessage("cancel");
-                });
-            }
-        });
-        menu.addItem({
-            icon: "iconFeedback",
-            label: "Message",
-            click: () => {
-                showMessage(this.i18n.helloPlugin);
-            }
-        });
         menu.addItem({
             icon: "iconInfo",
             label: "Dialog",
-            click: () => this.openHelloInDialog()
+            accelerator: this.commands[0].customHotkey,
+            click: this.showDialog
         });
-        menu.addItem({
-            icon: "iconLayoutBottom",
-            label: "Open Tab",
-            click: () => {
-                openTab({
-                    custom: {
-                        icon: "iconEmoji",
-                        title: "Custom Tab",
-                        data: {
-                            text: "This is my custom tab",
+        if (!this.isMobile) {
+            menu.addItem({
+                icon: "iconLayoutBottom",
+                label: "Open Custom Tab",
+                click: () => {
+                    const tab = openTab({
+                        app: this.app,
+                        custom: {
+                            icon: "iconFace",
+                            title: "Custom Tab",
+                            data: {
+                                text: "This is my custom tab",
+                            },
+                            fn: this.customTab
                         },
-                        fn: this.customTab
-                    },
-                });
-            }
-        });
-        menu.addItem({
-            icon: "iconLayout",
-            label: "Open Float Layer(open help)",
-            click: () => {
-                this.addFloatLayer({
-                    ids: ["20230523173319-xj1l3qu", "20230523173321-55o0w2n"],
-                    defIds: ["20230523173323-imgm9tp", "20230523173324-cxu98t3"],
-                    x: window.innerWidth - 768 - 120,
-                    y: 32
-                });
-            }
-        });
-        menu.addItem({
-            icon: "iconTrashcan",
-            label: "Remove Data",
-            click: () => {
-                this.removeData(STORAGE_NAME).then(() => {
-                    this.data[STORAGE_NAME] = {readonlyText: "Readonly"};
-                });
-            }
-        });
+                    });
+                    console.log(tab)
+                }
+            });
+            menu.addItem({
+                icon: "iconLayoutBottom",
+                label: "Open Asset Tab(open help first)",
+                click: () => {
+                    const tab = openTab({
+                        app: this.app,
+                        asset: {
+                            path: "assets/paragraph-20210512165953-ag1nib4.svg"
+                        }
+                    });
+                    console.log(tab)
+                }
+            });
+            menu.addItem({
+                icon: "iconLayoutBottom",
+                label: "Open Doc Tab(open help first)",
+                click: async () => {
+                    const tab = await openTab({
+                        app: this.app,
+                        doc: {
+                            id: "20200812220555-lj3enxa",
+                        }
+                    });
+                    console.log(tab)
+                }
+            });
+            menu.addItem({
+                icon: "iconLayoutBottom",
+                label: "Open Search Tab",
+                click: () => {
+                    const tab = openTab({
+                        app: this.app,
+                        search: {
+                            k: "SiYuan"
+                        }
+                    });
+                    console.log(tab)
+                }
+            });
+            menu.addItem({
+                icon: "iconLayoutBottom",
+                label: "Open Card Tab",
+                click: () => {
+                    const tab = openTab({
+                        app: this.app,
+                        card: {
+                            type: "all"
+                        }
+                    });
+                    console.log(tab)
+                }
+            });
+            menu.addItem({
+                icon: "iconLayout",
+                label: "Open Float Layer(open help first)",
+                click: () => {
+                    this.addFloatLayer({
+                        ids: ["20210428212840-8rqwn5o", "20201225220955-l154bn4"],
+                        defIds: ["20230415111858-vgohvf3", "20200813131152-0wk5akh"],
+                        x: window.innerWidth - 768 - 120,
+                        y: 32
+                    });
+                }
+            });
+        }
         menu.addItem({
             icon: "iconScrollHoriz",
             label: "Event Bus",
@@ -178,13 +285,13 @@ export default class SamplePlugin extends Plugin {
                 icon: "iconSelect",
                 label: "On ws-main",
                 click: () => {
-                    this.eventBus.on("ws-main", this.wsEvent);
+                    this.eventBus.on("ws-main", this.eventBusLog);
                 }
             }, {
                 icon: "iconClose",
                 label: "Off ws-main",
                 click: () => {
-                    this.eventBus.off("ws-main", this.wsEvent);
+                    this.eventBus.off("ws-main", this.eventBusLog);
                 }
             }, {
                 icon: "iconSelect",
@@ -202,35 +309,59 @@ export default class SamplePlugin extends Plugin {
                 icon: "iconSelect",
                 label: "On click-pdf",
                 click: () => {
-                    this.eventBus.on("click-pdf", this.wsEvent);
+                    this.eventBus.on("click-pdf", this.eventBusLog);
                 }
             }, {
                 icon: "iconClose",
                 label: "Off click-pdf",
                 click: () => {
-                    this.eventBus.off("click-pdf", this.wsEvent);
+                    this.eventBus.off("click-pdf", this.eventBusLog);
                 }
             }, {
                 icon: "iconSelect",
                 label: "On click-editorcontent",
                 click: () => {
-                    this.eventBus.on("click-editorcontent", this.wsEvent);
+                    this.eventBus.on("click-editorcontent", this.eventBusLog);
                 }
             }, {
                 icon: "iconClose",
                 label: "Off click-editorcontent",
                 click: () => {
-                    this.eventBus.off("click-editorcontent", this.wsEvent);
+                    this.eventBus.off("click-editorcontent", this.eventBusLog);
+                }
+            }, {
+                icon: "iconSelect",
+                label: "On click-editortitleicon",
+                click: () => {
+                    this.eventBus.on("click-editortitleicon", this.eventBusLog);
+                }
+            }, {
+                icon: "iconClose",
+                label: "Off click-editortitleicon",
+                click: () => {
+                    this.eventBus.off("click-editortitleicon", this.eventBusLog);
+                }
+            }, {
+                icon: "iconSelect",
+                label: "On open-noneditableblock",
+                click: () => {
+                    this.eventBus.on("open-noneditableblock", this.eventBusLog);
+                }
+            }, {
+                icon: "iconClose",
+                label: "Off open-noneditableblock",
+                click: () => {
+                    this.eventBus.off("open-noneditableblock", this.eventBusLog);
                 }
             }]
         });
         menu.addSeparator();
         menu.addItem({
             icon: "iconSparkles",
-            label: this.data[STORAGE_NAME] || "Readonly",
+            label: this.data[STORAGE_NAME].readonlyText || "Readonly",
             type: "readonly",
         });
-        if (isMobile()) {
+        if (this.isMobile) {
             menu.fullscreen();
         } else {
             menu.open({
@@ -241,22 +372,6 @@ export default class SamplePlugin extends Plugin {
         }
     }
 
-    openSetting(): void {
-        let dialog = new Dialog({
-            title: "SettingPannel",
-            content: `<div id="SettingPanel"></div>`,
-            width: "600px",
-            destroyCallback: (options) => {
-                console.log("destroyCallback", options);
-                //You must destroy the component when the dialog is closed
-                pannel.$destroy();
-            }
-        });
-        let pannel = new SettingPannel({
-            target: dialog.element.querySelector("#SettingPanel"),
-        });
-    }
-
     private openHelloInDialog() {
         let dialog = new Dialog({
             title: "Hello World",
diff --git a/src/siyuan.d.ts b/src/siyuan.d.ts
new file mode 100644
index 0000000..4c74dc5
--- /dev/null
+++ b/src/siyuan.d.ts
@@ -0,0 +1,424 @@
+type TEventBus = "ws-main" | "click-blockicon" | "click-editorcontent" | "click-pdf" |
+    "click-editortitleicon" | "open-noneditableblock"
+
+type TCardType = "doc" | "notebook" | "all"
+
+declare global {
+    interface Window {
+        Lute: Lute
+    }
+}
+
+interface ITab {
+    id: string;
+    headElement: HTMLElement;
+    panelElement: HTMLElement;
+    model: IModel;
+    title: string;
+    icon: string;
+    docIcon: string;
+    updateTitle: (title: string) => void;
+    pin: () => void;
+    unpin: () => void;
+    setDocIcon: (icon: string) => void;
+    close: () => void;
+}
+
+interface IModel {
+    element: Element;
+    tab: ITab;
+    data: any;
+    type: string;
+}
+
+interface IObject {
+    [key: string]: string;
+}
+
+interface ILuteNode {
+    TokensStr: () => string;
+    __internal_object__: {
+        Parent: {
+            Type: number,
+        },
+        HeadingLevel: string,
+    };
+}
+
+interface ISearchOption {
+    page?: number
+    group?: number,  // 0:不分组,1:按文档分组
+    hasReplace?: boolean,
+    method?: number //  0:文本,1:查询语法,2:SQL,3:正则表达式
+    hPath?: string
+    idPath?: string[]
+    k: string
+    r?: string
+    types?: {
+        mathBlock: boolean
+        table: boolean
+        blockquote: boolean
+        superBlock: boolean
+        paragraph: boolean
+        document: boolean
+        heading: boolean
+        list: boolean
+        listItem: boolean
+        codeBlock: boolean
+        htmlBlock: boolean
+        embedBlock: boolean
+    }
+}
+
+interface IWebSocketData {
+    cmd: string
+    callback?: string
+    data: any
+    msg: string
+    code: number
+    sid: string
+}
+
+declare interface IPluginDockTab {
+    position: "LeftTop" | "LeftBottom" | "RightTop" | "RightBottom" | "BottomLeft" | "BottomRight",
+    size: { width: number, height: number },
+    icon: string,
+    hotkey?: string,
+    title: string,
+    index?: number,
+    show?: boolean
+}
+
+interface IMenuItemOption {
+    label?: string,
+    click?: (element: HTMLElement) => void,
+    type?: "separator" | "submenu" | "readonly",
+    accelerator?: string,
+    action?: string,
+    id?: string,
+    submenu?: IMenuItemOption[]
+    disabled?: boolean
+    icon?: string
+    iconHTML?: string
+    current?: boolean
+    bind?: (element: HTMLElement) => void
+    index?: number
+    element?: HTMLElement
+}
+
+interface ICommandOption {
+    langKey: string, // 多语言 key
+    /**
+     * 目前需使用 MacOS 符号标识,顺序按照 ⌥⇧⌘,入 ⌥⇧⌘A
+     * "Ctrl": "⌘",
+     * "Shift": "⇧",
+     * "Alt": "⌥",
+     * "Tab": "⇥",
+     * "Backspace": "⌫",
+     * "Delete": "⌦",
+     * "Enter": "↩",
+     */
+    hotkey: string,
+    customHotkey?: string,
+    callback?: () => void
+    fileTreeCallback?: (file: any) => void
+    editorCallback?: (protyle: any) => void
+    dockCallback?: (element: HTMLElement) => void
+}
+
+export function fetchPost(url: string, data?: any, callback?: (response: IWebSocketData) => void, headers?: IObject): void;
+
+export function fetchSyncPost(url: string, data?: any): Promise<IWebSocketData>;
+
+export function fetchGet(url: string, callback: (response: IWebSocketData) => void): void;
+
+export function openTab(options: {
+    app: App,
+    doc?: {
+        id: string,     // 块 id
+        action?: string [] // cb-get-all:获取所有内容;cb-get-focus:打开后光标定位在 id 所在的块;cb-get-hl: 打开后 id 块高亮
+        zoomIn?: boolean // 是否缩放
+    },
+    pdf?: {
+        path: string,
+        page?: number,  // pdf 页码
+        id?: string,    // File Annotation id
+    },
+    asset?: {
+        path: string,
+    },
+    search?: ISearchOption
+    card?: {
+        type: TCardType,
+        id?: string, //  cardType 为 all 时不传,否则传文档或笔记本 id
+        title?: string //  cardType 为 all 时不传,否则传文档或笔记本名称
+    },
+    custom?: {
+        title: string,
+        icon: string,
+        data?: any
+        fn?: () => IModel,
+    }
+    position?: "right" | "bottom",
+    keepCursor?: boolean // 是否跳转到新 tab 上
+    removeCurrentTab?: boolean // 在当前页签打开时需移除原有页签
+    afterOpen?: () => void // 打开后回调
+}): ITab
+
+export function getFrontend(): "desktop" | "desktop-window" | "mobile" | "browser-desktop" | "browser-mobile";
+
+export function getBackend(): "windows" | "linux" | "darwin" | "docker" | "android" | "ios"
+
+export function adaptHotkey(hotkey: string): string;
+
+export function confirm(title: string, text: string, confirmCallback?: () => void, cancelCallback?: () => void): void;
+
+/**
+ * @param timeout - ms. 0: manual close;-1: always show; 6000: default
+ * @param {string} [type=info]
+ */
+export function showMessage(text: string, timeout?: number, type?: "info" | "error", id?: string): void;
+
+export class App {
+    plugins: Plugin[];
+}
+
+export abstract class Plugin {
+    eventBus: EventBus;
+    i18n: IObject;
+    data: any;
+    name: string;
+    app: App;
+    commands: ICommandOption[];
+
+    constructor(options: {
+        app: App,
+        name: string,
+        i18n: IObject
+    })
+
+    onload(): void;
+
+    onunload(): void;
+
+    onLayoutReady(): void;
+
+    /**
+     * Must be executed before the synchronous function.
+     * @param {string} [options.position=right]
+     */
+    addTopBar(options: {
+        icon: string,
+        title: string,
+        callback: (event: MouseEvent) => void
+        position?: "right" | "left"
+    }): HTMLElement;
+
+    /**
+     * Must be executed before the synchronous function.
+     * @param {string} [options.position=right]
+     */
+    addStatusBar(options: {
+        element: HTMLElement,
+        position?: "right" | "left"
+    }): HTMLElement
+
+    openSetting(): void
+
+    loadData(storageName: string): Promise<any>;
+
+    saveData(storageName: string, content: any): Promise<void>;
+
+    removeData(storageName: string): Promise<any>;
+
+    addIcons(svg: string): void;
+
+    /**
+     * Must be executed before the synchronous function.
+     */
+    addTab(options: {
+        type: string,
+        destroy?: () => void,
+        resize?: () => void,
+        update?: () => void,
+        init: () => void
+    }): () => IModel
+
+    /**
+     * Must be executed before the synchronous function.
+     */
+    addDock(options: {
+        config: IPluginDockTab,
+        data: any,
+        type: string,
+        destroy?: () => void,
+        resize?: () => void,
+        update?: () => void,
+        init: () => void
+    }): { config: IPluginDockTab, model: IModel }
+
+    addCommand(options: ICommandOption): void
+
+    addFloatLayer(options: {
+        ids: string[],
+        defIds?: string[],
+        x?: number,
+        y?: number,
+        targetElement?: HTMLElement
+    }): void
+}
+
+export class EventBus {
+    on(type: TEventBus, listener: (event: CustomEvent<any>) => void): void;
+
+    once(type: TEventBus, listener: (event: CustomEvent<any>) => void): void;
+
+    off(type: TEventBus, listener: (event: CustomEvent<any>) => void): void;
+
+    emit(type: TEventBus, detail?: any): boolean;
+}
+
+export class Dialog {
+
+    element: HTMLElement;
+
+    constructor(options: {
+        title?: string,
+        transparent?: boolean,
+        content: string,
+        width?: string
+        height?: string,
+        destroyCallback?: (options?: IObject) => void
+        disableClose?: boolean
+        disableAnimation?: boolean
+    });
+
+    destroy(options?: IObject): void;
+
+    bindInput(inputElement: HTMLInputElement | HTMLTextAreaElement, enterEvent?: () => void): void;
+}
+
+export class Menu {
+    constructor(id?: string, closeCallback?: () => void);
+
+    showSubMenu(subMenuElement: HTMLElement): void;
+
+    addItem(options: IMenuItemOption): HTMLElement;
+
+    addSeparator(index?: number): void;
+
+    open(options: { x: number, y: number, h?: number, w?: number, isLeft?: boolean }): void;
+
+    /**
+     * @param {string} [position=all]
+     */
+    fullscreen(position?: "bottom" | "all"): void;
+
+    close(): void;
+}
+
+declare class Lute {
+    public static WalkStop: number;
+    public static WalkSkipChildren: number;
+    public static WalkContinue: number;
+    public static Version: string;
+    public static Caret: string;
+
+    public static New(): Lute;
+
+    public static EChartsMindmapStr(text: string): string;
+
+    public static NewNodeID(): string;
+
+    public static Sanitize(html: string): string;
+
+    public static EscapeHTMLStr(str: string): string;
+
+    public static UnEscapeHTMLStr(str: string): string;
+
+    public static GetHeadingID(node: ILuteNode): string;
+
+    public static BlockDOM2Content(html: string): string;
+
+    private constructor();
+
+    public BlockDOM2Content(text: string): string;
+
+    public BlockDOM2EscapeMarkerContent(text: string): string;
+
+    public SetTextMark(enable: boolean): void;
+
+    public SetHeadingID(enable: boolean): void;
+
+    public SetProtyleMarkNetImg(enable: boolean): void;
+
+    public SetSpellcheck(enable: boolean): void;
+
+    public SetFileAnnotationRef(enable: boolean): void;
+
+    public SetSetext(enable: boolean): void;
+
+    public SetYamlFrontMatter(enable: boolean): void;
+
+    public SetChineseParagraphBeginningSpace(enable: boolean): void;
+
+    public SetRenderListStyle(enable: boolean): void;
+
+    public SetImgPathAllowSpace(enable: boolean): void;
+
+    public SetKramdownIAL(enable: boolean): void;
+
+    public BlockDOM2Md(html: string): string;
+
+    public BlockDOM2StdMd(html: string): string;
+
+    public SetGitConflict(enable: boolean): void;
+
+    public SetSuperBlock(enable: boolean): void;
+
+    public SetTag(enable: boolean): void;
+
+    public SetMark(enable: boolean): void;
+
+    public SetSub(enable: boolean): void;
+
+    public SetSup(enable: boolean): void;
+
+    public SetBlockRef(enable: boolean): void;
+
+    public SetSanitize(enable: boolean): void;
+
+    public SetHeadingAnchor(enable: boolean): void;
+
+    public SetImageLazyLoading(imagePath: string): void;
+
+    public SetInlineMathAllowDigitAfterOpenMarker(enable: boolean): void;
+
+    public SetToC(enable: boolean): void;
+
+    public SetIndentCodeBlock(enable: boolean): void;
+
+    public SetParagraphBeginningSpace(enable: boolean): void;
+
+    public SetFootnotes(enable: boolean): void;
+
+    public SetLinkRef(enalbe: boolean): void;
+
+    public SetEmojiSite(emojiSite: string): void;
+
+    public PutEmojis(emojis: IObject): void;
+
+    public SpinBlockDOM(html: string): string;
+
+    public Md2BlockDOM(html: string): string;
+
+    public SetProtyleWYSIWYG(wysiwyg: boolean): void;
+
+    public MarkdownStr(name: string, md: string): string;
+
+    public IsValidLinkDest(text: string): boolean;
+
+    public BlockDOM2InlineBlockDOM(html: string): string;
+
+    public BlockDOM2HTML(html: string): string;
+}
\ No newline at end of file