mirror of
https://github.com/logseq/logseq.git
synced 2026-04-30 17:06:23 +00:00
493 lines
11 KiB
TypeScript
493 lines
11 KiB
TypeScript
import EventEmitter from 'eventemitter3'
|
|
import * as CSS from 'csstype'
|
|
import { LSPluginCaller } from './LSPlugin.caller'
|
|
|
|
export type PluginLocalIdentity = string
|
|
|
|
export type ThemeOptions = {
|
|
name: string
|
|
url: string
|
|
description?: string
|
|
mode?: 'dark' | 'light'
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
export type StyleString = string;
|
|
export type StyleOptions = {
|
|
key?: string
|
|
style: StyleString
|
|
}
|
|
|
|
export type UIBaseOptions = {
|
|
key?: string
|
|
replace?: boolean
|
|
template: string
|
|
}
|
|
|
|
export type UIPathIdentity = {
|
|
/**
|
|
* DOM selector
|
|
*/
|
|
path: string
|
|
}
|
|
|
|
export type UISlotIdentity = {
|
|
/**
|
|
* Slot key
|
|
*/
|
|
slot: string
|
|
}
|
|
|
|
export type UISlotOptions = UIBaseOptions & UISlotIdentity
|
|
|
|
export type UIPathOptions = UIBaseOptions & UIPathIdentity
|
|
|
|
export type UIOptions = UIPathOptions | UISlotOptions
|
|
|
|
export interface LSPluginPkgConfig {
|
|
id: PluginLocalIdentity
|
|
mode: 'shadow' | 'iframe'
|
|
themes: Array<ThemeOptions>
|
|
icon: string
|
|
}
|
|
|
|
export interface LSPluginBaseInfo {
|
|
id: string // should be unique
|
|
mode: 'shadow' | 'iframe'
|
|
|
|
settings: {
|
|
disabled: boolean
|
|
[key: string]: any
|
|
},
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
export type IHookEvent = {
|
|
[key: string]: any
|
|
}
|
|
|
|
export type IUserOffHook = () => void
|
|
export type IUserHook<E = any, R = IUserOffHook> = (callback: (e: IHookEvent & E) => void) => IUserOffHook
|
|
export type IUserSlotHook<E = any> = (callback: (e: IHookEvent & UISlotIdentity & E) => void) => void
|
|
|
|
export type BlockID = number
|
|
export type BlockUUID = string
|
|
export type BlockUUIDTuple = ['uuid', BlockUUID]
|
|
|
|
export type IEntityID = { id: BlockID }
|
|
export type IBatchBlock = { content: string, properties?: Record<string, any>, children?: Array<IBatchBlock> }
|
|
|
|
export interface AppUserInfo {
|
|
[key: string]: any
|
|
}
|
|
|
|
/**
|
|
* User's app configurations
|
|
*/
|
|
export interface AppUserConfigs {
|
|
preferredThemeMode: 'dark' | 'light'
|
|
preferredFormat: 'markdown' | 'org'
|
|
preferredLanguage: string
|
|
preferredWorkflow: string
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
/**
|
|
* In Logseq, a graph represents a repository of connected pages and blocks
|
|
*/
|
|
export interface AppGraphInfo {
|
|
name: string
|
|
url: string
|
|
path: string
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
/**
|
|
* Block - Logseq's fundamental data structure.
|
|
*/
|
|
export interface BlockEntity {
|
|
id: BlockID // db id
|
|
uuid: BlockUUID
|
|
left: IEntityID
|
|
format: 'markdown' | 'org'
|
|
parent: IEntityID
|
|
unordered: boolean
|
|
content: string
|
|
page: IEntityID
|
|
|
|
// optional fields in dummy page
|
|
anchor?: string
|
|
body?: any
|
|
children?: Array<BlockEntity | BlockUUIDTuple>
|
|
container?: string
|
|
file?: IEntityID
|
|
level?: number
|
|
meta?: { timestamps: any, properties: any, startPos: number, endPos: number }
|
|
title?: Array<any>
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
/**
|
|
* Page is just a block with some specific properties.
|
|
*/
|
|
export interface PageEntity {
|
|
id: BlockID
|
|
uuid: BlockUUID
|
|
name: string
|
|
originalName: string
|
|
'journal?': boolean
|
|
|
|
file?: IEntityID
|
|
format?: 'markdown' | 'org'
|
|
journalDay?: number
|
|
}
|
|
|
|
export type BlockIdentity = BlockUUID | Pick<BlockEntity, 'uuid'>
|
|
export type BlockPageName = string
|
|
export type PageIdentity = BlockPageName | BlockIdentity
|
|
export type SlashCommandActionCmd =
|
|
'editor/input'
|
|
| 'editor/hook'
|
|
| 'editor/clear-current-slash'
|
|
| 'editor/restore-saved-cursor'
|
|
export type SlashCommandAction = [cmd: SlashCommandActionCmd, ...args: any]
|
|
export type BlockCommandCallback = (e: IHookEvent & { uuid: BlockUUID }) => Promise<void>
|
|
export type BlockCursorPosition = { left: number, top: number, height: number, pos: number, rect: DOMRect }
|
|
|
|
/**
|
|
* App level APIs
|
|
*/
|
|
export interface IAppProxy {
|
|
getUserInfo: () => Promise<AppUserInfo | null>
|
|
|
|
getUserConfigs: () => Promise<AppUserConfigs>
|
|
|
|
// native
|
|
relaunch: () => Promise<void>
|
|
quit: () => Promise<void>
|
|
openExternalLink: (url: string) => Promise<void>
|
|
|
|
// graph
|
|
getCurrentGraph: () => Promise<AppGraphInfo | null>
|
|
|
|
// router
|
|
pushState: (k: string, params?: {}) => void
|
|
replaceState: (k: string, params?: {}) => void
|
|
|
|
// ui
|
|
showMsg: (content: string, status?: 'success' | 'warning' | string) => void
|
|
setZoomFactor: (factor: number) => void
|
|
|
|
registerUIItem: (
|
|
type: 'toolbar' | 'page',
|
|
opts: { key: string, template: string }
|
|
) => boolean
|
|
|
|
// events
|
|
onCurrentGraphChanged: IUserHook
|
|
onThemeModeChanged: IUserHook<{ mode: 'dark' | 'light' }>
|
|
onBlockRendererSlotted: IUserSlotHook<{ uuid: BlockUUID }>
|
|
onPageHeadActionsSlotted: IUserSlotHook
|
|
onRouteChanged: IUserHook<{ path: string, template: string }>
|
|
onSidebarVisibleChanged: IUserHook<{ visible: boolean }>
|
|
}
|
|
|
|
/**
|
|
* Editor related APIs
|
|
*/
|
|
export interface IEditorProxy extends Record<string, any> {
|
|
/**
|
|
* register a custom command which will be added to the Logseq slash command list
|
|
*
|
|
* @param tag - displayed name of command
|
|
* @param action - can be a single callback function to run when the command is called, or an array of fixed commands with arguments
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.Editor.registerSlashCommand("Say Hi", () => {
|
|
* console.log('Hi!')
|
|
* })
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.Editor.registerSlashCommand("💥 Big Bang", [
|
|
* ["editor/hook", "customCallback"],
|
|
* ["editor/clear-current-slash"],
|
|
* ]);
|
|
* ```
|
|
*/
|
|
registerSlashCommand: (
|
|
tag: string,
|
|
action: BlockCommandCallback | Array<SlashCommandAction>
|
|
) => boolean
|
|
|
|
/**
|
|
* register a custom command in the block context menu (triggered by right clicking the block dot)
|
|
* @param tag - displayed name of command
|
|
* @param action - can be a single callback function to run when the command is called
|
|
*/
|
|
registerBlockContextMenu: (
|
|
tag: string,
|
|
action: BlockCommandCallback
|
|
) => boolean
|
|
|
|
// block related APIs
|
|
|
|
checkEditing: () => Promise<BlockUUID | boolean>
|
|
|
|
/**
|
|
* insert a string at the current cursor
|
|
*/
|
|
insertAtEditingCursor: (content: string) => Promise<void>
|
|
|
|
restoreEditingCursor: () => Promise<void>
|
|
|
|
exitEditingMode: (selectBlock?: boolean) => Promise<void>
|
|
|
|
getEditingCursorPosition: () => Promise<BlockCursorPosition | null>
|
|
|
|
getEditingBlockContent: () => Promise<string>
|
|
|
|
getCurrentPage: () => Promise<PageEntity | BlockEntity | null>
|
|
|
|
getCurrentBlock: () => Promise<BlockEntity | null>
|
|
|
|
/**
|
|
* get all blocks of the current page as a tree structure
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const blocks = await logseq.Editor.getCurrentPageBlocksTree()
|
|
* initMindMap(blocks)
|
|
* ```
|
|
*/
|
|
getCurrentPageBlocksTree: () => Promise<Array<BlockEntity>>
|
|
|
|
/**
|
|
* get all blocks for the specified page
|
|
*
|
|
* @param srcPage - the page name or uuid
|
|
*/
|
|
getPageBlocksTree: (srcPage: PageIdentity) => Promise<Array<BlockEntity>>
|
|
|
|
insertBlock: (
|
|
srcBlock: BlockIdentity,
|
|
content: string,
|
|
opts?: Partial<{ before: boolean; sibling: boolean; properties: {} }>
|
|
) => Promise<BlockEntity | null>
|
|
|
|
insertBatchBlock: (
|
|
srcBlock: BlockIdentity,
|
|
batch: IBatchBlock | Array<IBatchBlock>,
|
|
opts?: Partial<{ before: boolean, sibling: boolean }>
|
|
) => Promise<Array<BlockEntity> | null>
|
|
|
|
updateBlock: (
|
|
srcBlock: BlockIdentity,
|
|
content: string,
|
|
opts?: Partial<{ properties: {} }>
|
|
) => Promise<void>
|
|
|
|
removeBlock: (
|
|
srcBlock: BlockIdentity
|
|
) => Promise<void>
|
|
|
|
getBlock: (
|
|
srcBlock: BlockIdentity | BlockID,
|
|
opts?: Partial<{ includeChildren: boolean }>
|
|
) => Promise<BlockEntity | null>
|
|
|
|
getPage: (
|
|
srcPage: PageIdentity | BlockID,
|
|
opts?: Partial<{ includeChildren: boolean }>
|
|
) => Promise<PageEntity | null>
|
|
|
|
getPreviousSiblingBlock: (
|
|
srcBlock: BlockIdentity
|
|
) => Promise<BlockEntity | null>
|
|
|
|
getNextSiblingBlock: (srcBlock: BlockIdentity) => Promise<BlockEntity | null>
|
|
|
|
moveBlock: (
|
|
srcBlock: BlockIdentity,
|
|
targetBlock: BlockIdentity,
|
|
opts?: Partial<{ before: boolean; children: boolean }>
|
|
) => Promise<void>
|
|
|
|
editBlock: (srcBlock: BlockIdentity, opts?: { pos: number }) => Promise<void>
|
|
|
|
upsertBlockProperty: (
|
|
block: BlockIdentity,
|
|
key: string,
|
|
value: any
|
|
) => Promise<void>
|
|
|
|
removeBlockProperty: (block: BlockIdentity, key: string) => Promise<void>
|
|
|
|
getBlockProperty: (block: BlockIdentity, key: string) => Promise<any>
|
|
|
|
getBlockProperties: (block: BlockIdentity) => Promise<any>
|
|
}
|
|
|
|
/**
|
|
* Datascript related APIs
|
|
*/
|
|
export interface IDBProxy {
|
|
/**
|
|
* Run a datascript query
|
|
*/
|
|
datascriptQuery: <T = any>(query: string) => Promise<T>
|
|
}
|
|
|
|
export interface ILSPluginThemeManager extends EventEmitter {
|
|
themes: Map<PluginLocalIdentity, Array<ThemeOptions>>
|
|
|
|
registerTheme (id: PluginLocalIdentity, opt: ThemeOptions): Promise<void>
|
|
|
|
unregisterTheme (id: PluginLocalIdentity): Promise<void>
|
|
|
|
selectTheme (opt?: ThemeOptions): Promise<void>
|
|
}
|
|
|
|
export type LSPluginUserEvents = 'ui:visible:changed' | 'settings:changed'
|
|
|
|
export interface ILSPluginUser extends EventEmitter<LSPluginUserEvents> {
|
|
/**
|
|
* Connection status with the main app
|
|
*/
|
|
connected: boolean
|
|
|
|
/**
|
|
* Duplex message caller
|
|
*/
|
|
caller: LSPluginCaller
|
|
|
|
/**
|
|
* The plugin configurations from package.json
|
|
*/
|
|
baseInfo: LSPluginBaseInfo
|
|
|
|
/**
|
|
* The plugin user settings
|
|
*/
|
|
settings?: LSPluginBaseInfo['settings']
|
|
|
|
/**
|
|
* The main Logseq app is ready to run the plugin
|
|
*
|
|
* @param model - same as the model in `provideModel`
|
|
*/
|
|
ready (model?: Record<string, any>): Promise<any>
|
|
|
|
/**
|
|
* @param callback - a function to run when the main Logseq app is ready
|
|
*/
|
|
ready (callback?: (e: any) => void | {}): Promise<any>
|
|
|
|
ready (
|
|
model?: Record<string, any>,
|
|
callback?: (e: any) => void | {}
|
|
): Promise<any>
|
|
|
|
beforeunload: (callback: () => Promise<void>) => void
|
|
|
|
/**
|
|
* Create a object to hold the methods referenced in `provideUI`
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.provideModel({
|
|
* openCalendar () {
|
|
* console.log('Open the calendar!')
|
|
* }
|
|
* })
|
|
* ```
|
|
*/
|
|
provideModel (model: Record<string, any>): this
|
|
|
|
/**
|
|
* Set the theme for the main Logseq app
|
|
*/
|
|
provideTheme (theme: ThemeOptions): this
|
|
|
|
/**
|
|
* Inject custom css for the main Logseq app
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.provideStyle(`
|
|
* @import url("https://at.alicdn.com/t/font_2409735_r7em724douf.css");
|
|
* )
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts
|
|
*
|
|
* ```
|
|
*/
|
|
provideStyle (style: StyleString | StyleOptions): this
|
|
|
|
/**
|
|
* Inject custom UI at specific DOM node.
|
|
* Event handlers can not be passed by string, so you need to create them in `provideModel`
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.provideUI({
|
|
* key: 'open-calendar',
|
|
* path: '#search',
|
|
* template: `
|
|
* <a data-on-click="openCalendar" onclick="alert('abc')" style="opacity: .6; display: inline-flex; padding-left: 3px;">
|
|
* <i class="iconfont icon-Calendaralt2"></i>
|
|
* </a>
|
|
* `
|
|
* })
|
|
* ```
|
|
*/
|
|
provideUI (ui: UIOptions): this
|
|
|
|
updateSettings (attrs: Record<string, any>): void
|
|
|
|
setMainUIAttrs (attrs: Record<string, any>): void
|
|
|
|
/**
|
|
* Set the style for the plugin's UI
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* logseq.setMainUIInlineStyle({
|
|
* position: 'fixed',
|
|
* zIndex: 11,
|
|
* })
|
|
* ```
|
|
*/
|
|
setMainUIInlineStyle (style: CSS.Properties): void
|
|
|
|
/**
|
|
* show the plugin's UI
|
|
*/
|
|
showMainUI (): void
|
|
|
|
/**
|
|
* hide the plugin's UI
|
|
*/
|
|
hideMainUI (opts?: { restoreEditingCursor: boolean }): void
|
|
|
|
/**
|
|
* toggle the plugin's UI
|
|
*/
|
|
toggleMainUI (): void
|
|
|
|
isMainUIVisible: boolean
|
|
|
|
App: IAppProxy & Record<string, any>
|
|
Editor: IEditorProxy & Record<string, any>
|
|
DB: IDBProxy
|
|
}
|