Files
logseq/libs/src/LSPlugin.ts
Sal Rahman 2dd0193166 Fix: update logseq.Editor.getPageBlocksTree's return type. (#12212)
Changes the logseq.Editor.getPageBlocksTree's return type from
Promise<Array<BlockEntity>> to Promise<Array<BlockEntity> | null>.

Closes #12211.

Co-authored-by: Charlie <xyhp915@qq.com>
2025-11-25 09:57:07 +08:00

1170 lines
29 KiB
TypeScript

import * as CSS from 'csstype'
import EventEmitter from 'eventemitter3'
import { LSPluginCaller } from './LSPlugin.caller'
import { LSPluginExperiments } from './modules/LSPlugin.Experiments'
import { IAsyncStorage, LSPluginFileStorage } from './modules/LSPlugin.Storage'
import { LSPluginRequest } from './modules/LSPlugin.Request'
export type WithOptional<T, K extends keyof T> = Omit<T, K> &
Partial<Pick<T, K>>
export type PluginLocalIdentity = string
export type ThemeMode = 'light' | 'dark'
export interface LegacyTheme {
name: string
url: string
description?: string
mode?: ThemeMode
pid: PluginLocalIdentity
}
export interface Theme extends LegacyTheme {
mode: ThemeMode
}
export type StyleString = string
export type StyleOptions = {
key?: string
style: StyleString
}
export type UIContainerAttrs = {
draggable: boolean
resizable: boolean
}
export type UIBaseOptions = {
key?: string
replace?: boolean
template: string | null
style?: CSS.Properties
attrs?: Record<string, string>
close?: 'outside' | string
reset?: boolean // reset slot content or not
}
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 = UIBaseOptions | UIPathOptions | UISlotOptions
export interface LSPluginPkgConfig {
id: PluginLocalIdentity
main: string
entry: string // alias of main
title: string
mode: 'shadow' | 'iframe'
themes: Theme[]
icon: string
/**
* Alternative entrypoint for development.
*/
devEntry: string
/**
* For legacy themes, do not use.
*/
theme: unknown
}
export interface LSPluginBaseInfo {
/**
* Must be unique.
*/
id: string
mode: 'shadow' | 'iframe'
settings: {
disabled: boolean
} & Record<string, unknown>
effect: boolean
/**
* For internal use only. Indicates if plugin is installed in dot root.
*/
iir: boolean
/**
* For internal use only.
*/
lsr: string
}
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 IUserConditionSlotHook<C = any, E = any> = (
condition: C,
callback: (e: IHookEvent & UISlotIdentity & E) => void
) => void
export type EntityID = number
export type BlockUUID = string
export type BlockUUIDTuple = ['uuid', BlockUUID]
export type IEntityID = { id: EntityID; [key: string]: any }
export type IBatchBlock = {
content: string
/**
* @NOTE: not supported for DB graph
*/
properties?: Record<string, any>
children?: Array<IBatchBlock>
}
export type IDatom = [e: number, a: string, v: any, t: number, added: boolean]
export type IGitResult = { stdout: string; stderr: string; exitCode: number }
export interface AppUserInfo {
[key: string]: any
}
export interface AppInfo {
version: string
supportDb: boolean
[key: string]: unknown
}
/**
* User's app configurations
*/
export interface AppUserConfigs {
preferredThemeMode: ThemeMode
preferredFormat: 'markdown' | 'org'
preferredDateFormat: string
preferredStartOfWeek: string
preferredLanguage: string
preferredWorkflow: string
currentGraph: string
showBracket: boolean
enabledFlashcards: boolean
enabledJournals: boolean
[key: string]: unknown
}
/**
* In Logseq, a graph represents a repository of connected pages and blocks
*/
export interface AppGraphInfo {
name: string
url: string
path: string
[key: string]: unknown
}
/**
* Block - Logseq's fundamental data structure.
*/
export interface BlockEntity {
id: EntityID // db id
uuid: BlockUUID
order: string
format: 'markdown' | 'org'
parent: IEntityID
title: string
fullTitle: string // replace block reference uuid with title text
content?: string // @deprecated. use :title instead!
page: IEntityID // owner page
createdAt: number
updatedAt: number
ident?: string // ident for property block
properties?: Record<string, any>
'collapsed?': boolean
// 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 }
marker?: string
[key: string]: unknown
}
/**
* Page is just a block with some specific properties.
*/
export interface PageEntity {
id: EntityID
uuid: BlockUUID
name: string
format: 'markdown' | 'org'
type: 'page' | 'journal' | 'whiteboard' | 'class' | 'property' | 'hidden'
updatedAt: number
createdAt: number
'journal?': boolean
title?: string
file?: IEntityID
originalName?: string
namespace?: IEntityID
children?: Array<PageEntity>
properties?: Record<string, any>
journalDay?: number
ident?: string
[key: string]: unknown
}
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 SimpleCommandCallback<E = any> = (e: IHookEvent & E) => void
export type BlockCommandCallback = (
e: IHookEvent & { uuid: BlockUUID }
) => Promise<void>
export type BlockCursorPosition = {
left: number
top: number
height: number
pos: number
rect: DOMRect
}
export type Keybinding = string | Array<string>
export type SimpleCommandKeybinding = {
mode?: 'global' | 'non-editing' | 'editing'
binding: Keybinding
mac?: string // special for Mac OS
}
export type SettingSchemaDesc = {
key: string
type: 'string' | 'number' | 'boolean' | 'enum' | 'object' | 'heading'
default: string | number | boolean | Array<any> | object | null
title: string
description: string // support markdown
inputAs?: 'color' | 'date' | 'datetime-local' | 'range' | 'textarea'
enumChoices?: Array<string>
enumPicker?: 'select' | 'radio' | 'checkbox' // default: select
}
export type ExternalCommandType =
| 'logseq.command/run'
| 'logseq.editor/cycle-todo'
| 'logseq.editor/down'
| 'logseq.editor/up'
| 'logseq.editor/expand-block-children'
| 'logseq.editor/collapse-block-children'
| 'logseq.editor/open-file-in-default-app'
| 'logseq.editor/open-file-in-directory'
| 'logseq.editor/select-all-blocks'
| 'logseq.editor/toggle-open-blocks'
| 'logseq.editor/zoom-in'
| 'logseq.editor/zoom-out'
| 'logseq.editor/indent'
| 'logseq.editor/outdent'
| 'logseq.editor/copy'
| 'logseq.editor/cut'
| 'logseq.go/home'
| 'logseq.go/journals'
| 'logseq.go/keyboard-shortcuts'
| 'logseq.go/next-journal'
| 'logseq.go/prev-journal'
| 'logseq.go/search'
| 'logseq.go/tomorrow'
| 'logseq.go/backward'
| 'logseq.go/forward'
| 'logseq.search/re-index'
| 'logseq.sidebar/clear'
| 'logseq.sidebar/open-today-page'
| 'logseq.ui/goto-plugins'
| 'logseq.ui/select-theme-color'
| 'logseq.ui/toggle-brackets'
| 'logseq.ui/toggle-contents'
| 'logseq.ui/toggle-document-mode'
| 'logseq.ui/toggle-help'
| 'logseq.ui/toggle-left-sidebar'
| 'logseq.ui/toggle-right-sidebar'
| 'logseq.ui/toggle-settings'
| 'logseq.ui/toggle-theme'
| 'logseq.ui/toggle-wide-mode'
export type UserProxyNSTags = 'app' | 'editor' | 'db' | 'git' | 'ui' | 'assets' | 'utils'
export type SearchIndiceInitStatus = boolean
export type SearchBlockItem = {
id: EntityID
uuid: BlockIdentity
content: string
page: EntityID
}
export type SearchPageItem = string
export type SearchFileItem = string
export interface IPluginSearchServiceHooks {
name: string
options?: Record<string, any>
onQuery: (
graph: string,
key: string,
opts: Partial<{ limit: number }>
) => Promise<{
graph: string
key: string
blocks?: Array<Partial<SearchBlockItem>>
pages?: Array<SearchPageItem>
files?: Array<SearchFileItem>
}>
onIndiceInit: (graph: string) => Promise<SearchIndiceInitStatus>
onIndiceReset: (graph: string) => Promise<void>
onBlocksChanged: (
graph: string,
changes: {
added: Array<SearchBlockItem>
removed: Array<EntityID>
}
) => Promise<void>
onGraphRemoved: (graph: string, opts?: {}) => Promise<any>
}
/**
* App level APIs
*/
export interface IAppProxy {
/**
* @added 0.0.4
* @param key
*/
getInfo: (key?: keyof AppInfo) => Promise<AppInfo | any>
getUserInfo: () => Promise<AppUserInfo | null>
getUserConfigs: () => Promise<AppUserConfigs>
// services
registerSearchService<T extends IPluginSearchServiceHooks>(s: T): void
// commands
registerCommand: (
type: string,
opts: {
key: string
label: string
desc?: string
palette?: boolean
keybinding?: SimpleCommandKeybinding
},
action: SimpleCommandCallback
) => void
registerCommandPalette: (
opts: {
key: string
label: string
keybinding?: SimpleCommandKeybinding
},
action: SimpleCommandCallback
) => void
/**
* Supported key names
* @link https://gist.github.com/xyhp915/d1a6d151a99f31647a95e59cdfbf4ddc
* @param keybinding
* @param action
*/
registerCommandShortcut: (
keybinding: SimpleCommandKeybinding | string,
action: SimpleCommandCallback,
opts?: Partial<{
key: string
label: string
desc: string
extras: Record<string, any>
}>
) => void
/**
* Supported all registered palette commands
* @param type
* @param args
*/
invokeExternalCommand: (
type: ExternalCommandType,
...args: Array<any>
) => Promise<void>
/**
* Call external plugin command provided by models or registered commands
* @added 0.0.13
* @param type `xx-plugin-id.commands.xx-key`, `xx-plugin-id.models.xx-key`
* @param args
*/
invokeExternalPlugin: (type: string, ...args: Array<any>) => Promise<unknown>
/**
* @added 0.0.13
* @param pid
*/
getExternalPlugin: (pid: string) => Promise<{} | null>
/**
* Get state from app store
* valid state is here
* https://github.com/logseq/logseq/blob/master/src/main/frontend/state.cljs#L27
*
* @example
* ```ts
* const isDocMode = await logseq.App.getStateFromStore('document/mode?')
* ```
* @param path
*/
getStateFromStore: <T = any>(path: string | Array<string>) => Promise<T>
setStateFromStore: (path: string | Array<string>, value: any) => Promise<void>
// native
relaunch: () => Promise<void>
quit: () => Promise<void>
openExternalLink: (url: string) => Promise<void>
/**
* @deprecated Using `logseq.Git.execCommand`
* @link https://github.com/desktop/dugite/blob/master/docs/api/exec.md
* @param args
*/
execGitCommand: (args: string[]) => Promise<string>
// graph
getCurrentGraph: () => Promise<AppGraphInfo | null>
checkCurrentIsDbGraph: () => Promise<Boolean>
getCurrentGraphConfigs: (...keys: string[]) => Promise<any>
setCurrentGraphConfigs: (configs: {}) => Promise<void>
getCurrentGraphFavorites: () => Promise<Array<string | PageEntity> | null>
getCurrentGraphRecent: () => Promise<Array<string | PageEntity> | null>
getCurrentGraphTemplates: () => Promise<Record<string, BlockEntity> | null>
// router
pushState: (
k: string,
params?: Record<string, any>,
query?: Record<string, any>
) => void
replaceState: (
k: string,
params?: Record<string, any>,
query?: Record<string, any>
) => void
// templates
getTemplate: (name: string) => Promise<BlockEntity | null>
existTemplate: (name: string) => Promise<Boolean>
createTemplate: (
target: BlockUUID,
name: string,
opts?: { overwrite: boolean }
) => Promise<any>
removeTemplate: (name: string) => Promise<any>
insertTemplate: (target: BlockUUID, name: string) => Promise<any>
setZoomFactor: (factor: number) => void
setFullScreen: (flag: boolean | 'toggle') => void
setLeftSidebarVisible: (flag: boolean | 'toggle') => void
setRightSidebarVisible: (flag: boolean | 'toggle') => void
clearRightSidebarBlocks: (opts?: { close: boolean }) => void
registerUIItem: (
type: 'toolbar' | 'pagebar',
opts: { key: string; template: string }
) => void
registerPageMenuItem: (
tag: string,
action: (e: IHookEvent & { page: string }) => void
) => void
// hook events
onCurrentGraphChanged: IUserHook
onGraphAfterIndexed: IUserHook<{ repo: string }>
onThemeModeChanged: IUserHook<{ mode: 'dark' | 'light' }>
onThemeChanged: IUserHook<
Partial<{ name: string; mode: string; pid: string; url: string }>>
onTodayJournalCreated: IUserHook<{ title: string }>
onBeforeCommandInvoked: (condition: ExternalCommandType | string, callback: (e: IHookEvent) => void) => IUserOffHook
onAfterCommandInvoked: (condition: ExternalCommandType | string, callback: (e: IHookEvent) => void) => IUserOffHook
/**
* provide ui slot to specific block with UUID
*
* @added 0.0.13
*/
onBlockRendererSlotted: IUserConditionSlotHook<
BlockUUID,
Omit<BlockEntity, 'children' | 'page'>
>
/**
* provide ui slot to block `renderer` macro for `{{renderer arg1, arg2}}`
*
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-pomodoro-timer
* @example
* ```ts
* // e.g. {{renderer :h1, hello world, green}}
*
* logseq.App.onMacroRendererSlotted(({ slot, payload: { arguments } }) => {
* let [type, text, color] = arguments
* if (type !== ':h1') return
* logseq.provideUI({
* key: 'h1-playground',
* slot, template: `
* <h2 style="color: ${color || 'red'}">${text}</h2>
* `,
* })
* })
* ```
*/
onMacroRendererSlotted: IUserSlotHook<{
payload: { arguments: Array<string>; uuid: string; [key: string]: any }
}>
onPageHeadActionsSlotted: IUserSlotHook
onRouteChanged: IUserHook<{ path: string; template: string }>
onSidebarVisibleChanged: IUserHook<{ visible: boolean }>
// internal
_installPluginHook: (pid: string, hook: string, opts?: any) => void
_uninstallPluginHook: (pid: string, hookOrAll: string | boolean) => void
}
/**
* 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 https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-slash-commands
*
* @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>
) => unknown
/**
* register a custom command in the block context menu (triggered by right-clicking the block dot)
* @param label - displayed name of command
* @param action - can be a single callback function to run when the command is called
*/
registerBlockContextMenuItem: (
label: string,
action: BlockCommandCallback
) => unknown
/**
* Current it's only available for pdf viewer
* @param label - displayed name of command
* @param action - callback for the clickable item
* @param opts - clearSelection: clear highlight selection when callback invoked
*/
registerHighlightContextMenuItem: (
label: string,
action: SimpleCommandCallback,
opts?: {
clearSelection: boolean
}
) => unknown
// block related APIs
checkEditing: () => Promise<BlockUUID | boolean>
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>
getSelectedBlocks: () => Promise<Array<BlockEntity> | null>
clearSelectedBlocks: () => Promise<void>
/**
* 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> | null>
/**
* get all page/block linked references
* @param srcPage
*/
getPageLinkedReferences: (
srcPage: PageIdentity
) => Promise<Array<[page: PageEntity, blocks: Array<BlockEntity>]> | null>
/**
* get flatten pages from top namespace
* @param namespace
*/
getPagesFromNamespace: (
namespace: BlockPageName
) => Promise<Array<PageEntity> | null>
/**
* construct pages tree from namespace pages
* @param namespace
*/
getPagesTreeFromNamespace: (
namespace: BlockPageName
) => Promise<Array<PageEntity> | null>
/**
* Create a unique UUID string which can then be assigned to a block.
* @added 0.0.8
*/
newBlockUUID: () => Promise<string>
isPageBlock: (block: BlockEntity | PageEntity) => Boolean
/**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-reddit-hot-news
*
* @param srcBlock
* @param content
* @param opts
*/
insertBlock: (
srcBlock: BlockIdentity,
content: string,
opts?: Partial<{
before: boolean
sibling: boolean
start: boolean
end: boolean
isPageBlock: boolean
focus: boolean
customUUID: string
properties: {}
}>
) => Promise<BlockEntity | null>
/**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-reddit-hot-news
*
* `keepUUID` will allow you to set a custom UUID for blocks by setting their properties.id
*/
insertBatchBlock: (
srcBlock: BlockIdentity,
batch: IBatchBlock | Array<IBatchBlock>,
opts?: Partial<{ before: boolean; sibling: boolean; keepUUID: boolean }>
) => Promise<Array<BlockEntity> | null>
updateBlock: (
srcBlock: BlockIdentity,
content: string,
opts?: Partial<{ properties: {} }>
) => Promise<void>
removeBlock: (srcBlock: BlockIdentity) => Promise<void>
getBlock: (
srcBlock: BlockIdentity | EntityID,
opts?: Partial<{ includeChildren: boolean }>
) => Promise<BlockEntity | null>
/**
* @example
*
* ```ts
* logseq.Editor.setBlockCollapsed('uuid', true)
* logseq.Editor.setBlockCollapsed('uuid', 'toggle')
* ```
* @param uuid
* @param opts
*/
setBlockCollapsed: (
uuid: BlockUUID,
opts: { flag: boolean | 'toggle' } | boolean | 'toggle'
) => Promise<void>
getPage: (
srcPage: PageIdentity | EntityID,
opts?: Partial<{ includeChildren: boolean }>
) => Promise<PageEntity | null>
createPage: (
pageName: BlockPageName,
properties?: {},
opts?: Partial<{
redirect: boolean
createFirstBlock: boolean
customUUID: string
format: BlockEntity['format']
journal: boolean
}>
) => Promise<PageEntity | null>
createJournalPage: (
date: string | Date
) => Promise<PageEntity | null>
deletePage: (pageName: BlockPageName) => Promise<void>
renamePage: (oldName: string, newName: string) => Promise<void>
getAllPages: (repo?: string) => Promise<PageEntity[] | null>
getAllTags: () => Promise<PageEntity[] | null>
getAllProperties: () => Promise<PageEntity[] | null>
getTagObjects: (nameOrIdent: string) => Promise<BlockEntity[] | null>
createTag: (tagName: string, opts?: Partial<{ uuid: string }>) => Promise<PageEntity | null>
getTag: (nameOrIdent: string) => Promise<PageEntity | null>
addTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
removeTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
addBlockTag: (blockId: BlockIdentity, tagId: BlockIdentity) => Promise<void>
removeBlockTag: (blockId: BlockIdentity, tagId: BlockIdentity) => Promise<void>
prependBlockInPage: (
page: PageIdentity,
content: string,
opts?: Partial<{ properties: {} }>
) => Promise<BlockEntity | null>
appendBlockInPage: (
page: PageIdentity,
content: string,
opts?: Partial<{ properties: {} }>
) => Promise<BlockEntity | 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>
selectBlock: (srcBlock: BlockIdentity) => Promise<void>
saveFocusedCodeEditorContent: () => Promise<void>
// property entity related APIs (DB only)
getProperty: (key: string) => Promise<BlockEntity | null>
// insert or update property entity
upsertProperty: (
key: string,
schema?: Partial<{
type: 'default' | 'number' | 'node' | 'date' | 'checkbox' | 'url' | string,
cardinality: 'many' | 'one',
hide: boolean
public: boolean
}>,
opts?: { name?: string }) => Promise<IEntityID>
// remove property entity
removeProperty: (key: string) => Promise<void>
// block property related APIs
upsertBlockProperty: (
block: BlockIdentity,
key: string,
value: any
) => Promise<void>
removeBlockProperty: (block: BlockIdentity, key: string) => Promise<void>
getBlockProperty: (block: BlockIdentity, key: string) => Promise<BlockEntity | unknown>
getBlockProperties: (block: BlockIdentity) => Promise<Record<string, any> | null>
getPageProperties: (page: PageIdentity) => Promise<Record<string, any> | null>
scrollToBlockInPage: (
pageName: BlockPageName,
blockId: BlockIdentity,
opts?: { replaceState: boolean }
) => void
openInRightSidebar: (id: BlockUUID | EntityID) => void
/**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator
*/
onInputSelectionEnd: IUserHook<{
caret: any
point: { x: number; y: number }
start: number
end: number
text: string
}>
}
/**
* Datascript related APIs
*/
export interface IDBProxy {
/**
* Run a DSL query
* @link https://docs.logseq.com/#/page/queries
* @param dsl
*/
q: <T = any>(dsl: string) => Promise<Array<T> | null>
/**
* Run a datascript query
*/
datascriptQuery: <T = any>(query: string, ...inputs: Array<any>) => Promise<T>
/**
* Hook all transaction data of DB
*
* @added 0.0.2
*/
onChanged: IUserHook<{
blocks: Array<BlockEntity>
txData: Array<IDatom>
txMeta?: { outlinerOp: string; [key: string]: any }
}>
/**
* Subscribe a specific block changed event
*
* @added 0.0.2
*/
onBlockChanged(
uuid: BlockUUID,
callback: (
block: BlockEntity,
txData: Array<IDatom>,
txMeta?: { outlinerOp: string; [key: string]: any }
) => void
): IUserOffHook
}
/**
* Git related APIS
*/
export interface IGitProxy {
/**
* @added 0.0.2
* @link https://github.com/desktop/dugite/blob/master/docs/api/exec.md
* @param args
*/
execCommand: (args: string[]) => Promise<IGitResult>
loadIgnoreFile: () => Promise<string>
saveIgnoreFile: (content: string) => Promise<void>
}
/**
* UI related APIs
*/
export type UIMsgOptions = {
key: string
timeout: number // milliseconds. `0` indicate that keep showing
}
export type UIMsgKey = UIMsgOptions['key']
export interface IUIProxy {
showMsg: (
content: string,
status?: 'success' | 'warning' | 'error' | string,
opts?: Partial<UIMsgOptions>
) => Promise<UIMsgKey>
closeMsg: (key: UIMsgKey) => void
queryElementRect: (selector: string) => Promise<DOMRectReadOnly | null>
queryElementById: (id: string) => Promise<string | boolean>
checkSlotValid: (slot: UISlotIdentity['slot']) => Promise<boolean>
resolveThemeCssPropsVals: (props: string | Array<string>) => Promise<Record<string, string | undefined> | null>
}
export interface IUtilsProxy {
toJs: <R = unknown>(obj: {}) => Promise<R>
}
/**
* Assets related APIs
*/
export interface IAssetsProxy {
/**
* @added 0.0.2
* @param exts
*/
listFilesOfCurrentGraph(exts?: string | string[]): Promise<
Array<{
path: string
size: number
accessTime: number
modifiedTime: number
changeTime: number
birthTime: number
}>
>
/**
* @example https://github.com/logseq/logseq/pull/6488
* @added 0.0.10
*/
makeSandboxStorage(): IAsyncStorage
/**
* make assets scheme url based on current graph
* @added 0.0.15
* @param path
*/
makeUrl(path: string): Promise<string>
/**
* try to open asset type file in Logseq app
* @added 0.0.16
* @param path
*/
builtInOpen(path: string): Promise<boolean | undefined>
}
export interface ILSPluginThemeManager {
get themes(): Map<PluginLocalIdentity, Theme[]>
registerTheme(id: PluginLocalIdentity, opt: Theme): Promise<void>
unregisterTheme(id: PluginLocalIdentity, effect?: boolean): Promise<void>
selectTheme(
opt: Theme | LegacyTheme,
options: { effect?: boolean; emit?: boolean }
): 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: Theme): this
/**
* Inject custom css for the main Logseq app
*
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
* @example
* ```ts
* logseq.provideStyle(`
* @import url("https://at.alicdn.com/t/font_2409735_r7em724douf.css");
* )
* ```
*/
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 https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator
* @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
/**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
*
* @param schemas
*/
useSettingsSchema(schemas: Array<SettingSchemaDesc>): this
/**
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
*
* @param attrs
*/
updateSettings(attrs: Record<string, any>): void
onSettingsChanged<T = any>(cb: (a: T, b: T) => void): IUserOffHook
showSettingsUI(): void
hideSettingsUI(): void
setMainUIAttrs(attrs: Record<string, any>): void
/**
* Set the style for the plugin's UI
*
* @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-awesome-fonts
* @example
* ```ts
* logseq.setMainUIInlineStyle({
* position: 'fixed',
* zIndex: 11,
* })
* ```
*/
setMainUIInlineStyle(style: CSS.Properties): void
/**
* show the plugin's UI
*/
showMainUI(opts?: { autoFocus: boolean }): void
/**
* hide the plugin's UI
*/
hideMainUI(opts?: { restoreEditingCursor: boolean }): void
/**
* toggle the plugin's UI
*/
toggleMainUI(): void
isMainUIVisible: boolean
resolveResourceFullUrl(filePath: string): string
App: IAppProxy
Editor: IEditorProxy
DB: IDBProxy
Git: IGitProxy
UI: IUIProxy
Assets: IAssetsProxy
Request: LSPluginRequest
FileStorage: LSPluginFileStorage
Experiments: LSPluginExperiments
}