Plugin Migration Guide from v5 to v6
New ipm CLI tool
In v6, there is a new CLI tool named ipm (Inkdrop Plugin Manager) for publishing plugins.
npm install -g @inkdropapp/ipm-cli
ipm configure
Check out the repository for more details.
New TypeScript definitions
TypeScript definitions for Inkdrop v6 are now available at @inkdropapp/types. You can install them to get type-checking and autocompletion for the Inkdrop API in your plugin:
npm install --save-dev @inkdropapp/types
@electron/remote is deprecated
remote.dialog → inkdrop.dialog
Before:
const remote = require('@electron/remote')
const { dialog } = remote
return dialog.showOpenDialog(
inkdrop.window,
{
...
})
After:
return inkdrop.dialog.showOpenDialog({
...
})
inkdrop.window argument is no longer required.inkdrop.window.on()
Before:
inkdrop.window.on('focus', this.handleAppFocus)
After:
const sub = inkdrop.window.onFocus(this.handleAppFocus)
// Unsubscribe
sub.dispose()
activate() receives the inkdrop environment
In v6, the plugin's activate() function is called with the inkdrop environment instance as the first argument, followed by the persisted package state.
Before:
module.exports = {
activate() {
inkdrop.components.registerClass(MyComponent)
}
}
After:
import type { Environment } from '@inkdropapp/types'
module.exports = {
activate(env: Environment) {
env.components.registerClass(MyComponent)
}
}
A future release will deprecate the global inkdrop reference for sandboxing,
so please update your plugin to use the argument form. The global inkdrop
reference still works for backward compatibility at the moment.
Since the inkdrop environment is now passed as an argument rather than read from the global scope, you need a way to share it across the other modules of your plugin. A common pattern is to capture the instance in a dedicated module that exposes a getter and setter:
import type { Environment } from '@inkdropapp/types'
/**
* Captures the `Environment` instance handed to `activate()` so the plugin's
* other modules can reach it without touching the (discouraged) global
* `inkdrop` variable.
*/
let captured: Environment | undefined
export function setEnv(env: Environment | undefined): void {
captured = env
}
export function getEnv(): Environment {
if (!captured) {
throw new Error('env accessed before activate()')
}
return captured
}
Then call setEnv from activate() so the rest of your plugin can retrieve the environment via getEnv(), and clear it in deactivate() to avoid holding a stale reference:
import type { Environment, IInkdropPlugin } from '@inkdropapp/types'
import { setEnv } from './env'
class YourPlugin implements IInkdropPlugin {
activate(env: Environment) {
setEnv(env)
// initialize your plugin
}
deactivate(env: Environment) {
// cleanup
setEnv(undefined)
}
}
export default new YourPlugin()
onEditorLoad → ensureEditorLoaded
In v6, you can use ensureEditorLoaded instead of onEditorLoad to run code with the active editor.
onEditorLoad only fires when the editor component loads, so if the editor was already loaded by the time your plugin subscribed, you had to check for an active editor yourself and then also subscribe for future loads.
ensureEditorLoaded handles both cases: it invokes the callback immediately if an editor is already loaded, and otherwise waits for the next one to load.
Before:
function extendEditor() {
// ...
}
const editor = inkdrop.getActiveEditor()
if (editor) extendEditor()
inkdrop.onEditorLoad(() => {
extendEditor()
})
After:
inkdrop.ensureEditorLoaded((editor: EditorView) => {
// extend the editor
})
You no longer have to do the same dance of checking for an already-active editor before subscribing.
inkdrop.main.dataStore.getLocalDB() → inkdrop.localDB
CSS selectors for keymaps and commands
.mde-preview→.mde-preview-container
LESS is deprecated
The necessity of LESS has been less and less over the years, since CSS supports nested selectors and variables. In v6, the app has dropped support for LESS.
- Rename
.lessto.css
Before:
@primary-color: #ff0000;
.my-plugin {
.component {
color: @primary-color;
}
}
After:
:root {
--primary-color: #ff0000;
}
.my-plugin {
.component {
color: var(--primary-color);
}
}
Electron's clipboard is deprecated
Accessing the system clipboard through Electron's clipboard module is no longer supported. Use env.clipboard instead, which proxies the system clipboard over IPC.
Before:
const { clipboard } = require('electron')
const text = clipboard.readText()
clipboard.writeText('Hello, Inkdrop!')
After:
const text = env.clipboard.readText()
env.clipboard.writeText('Hello, Inkdrop!')
env.clipboard also provides readHTML(), readImageAsDataURL(), writeImage(dataUrl), availableFormats(), write({ text, html }), and saveAsImageAttachment(). See the clipboard property on the Environment for details.
Syntax themes
Syntax themes (packages with "theme": "syntax" in package.json) styled CodeMirror 5 in v5. Inkdrop 6 runs on CodeMirror 6, so a theme moves from styling CodeMirror's DOM directly to setting CSS variables, and from CodeMirror 5 mode tokens (.cm-*) to CodeMirror 6 / Lezer highlight classes (.tok-*).
The stock default-light and default-dark themes are maintained as reference implementations. Like every other plugin, themes also drop LESS for plain CSS, and should bump engines.inkdrop to ^6.x.
Editor chrome: DOM selectors → CSS variables
You no longer style CodeMirror's DOM. Replace the old .CodeMirror-* rules with the corresponding --editor-* variable, set in :root:
| v5 (CodeMirror 5) | v6 (CSS variable) |
|---|---|
.CodeMirror { background } | --editor-background-color |
.CodeMirror { color } | --editor-foreground-color |
.CodeMirror-cursor border / fat cursor | --editor-caret-color |
.CodeMirror-selected | --editor-selection-background |
.CodeMirror-focused .CodeMirror-selected | --editor-focused-selection-background |
.CodeMirror-gutters | --editor-gutter-background-color, --editor-gutter-border-right |
.CodeMirror-linenumber | --editor-gutter-color |
.CodeMirror-activeline-background | --editor-active-line-background-color |
.CodeMirror-matchingbracket | --editor-matching-bracket-outline, --editor-matching-bracket-background-color |
See the full list of --editor-* and --md-* variables at the top of the reference theme's styles/index.css.
Syntax tokens: .cm-* → .tok-*
CodeMirror 5 mode tokens become CodeMirror 6 / Lezer highlight classes, scoped under .cm-editor (and .mde-preview .codeblock for rendered preview code blocks):
| v5 (CodeMirror 5) | v6 (Lezer highlight class) |
|---|---|
.cm-keyword | .tok-keyword |
.cm-string | .tok-string |
.cm-comment | .tok-comment |
.cm-number | .tok-number |
.cm-variable | .tok-variable-name |
.cm-def | .tok-name.tok-definition, .tok-variable-name.tok-function |
.cm-type | .tok-type-name, .tok-class-name |
.cm-operator | .tok-operator |
.cm-tag | .tok-tag-name |
.cm-attribute | .tok-attribute-name |
.cm-atom | .tok-atom, .tok-bool |
.cm-meta | .tok-meta |
Before:
.cm-s-default {
.cm-keyword {
color: #c678dd;
}
.cm-string {
color: #98c379;
}
}
After:
.cm-editor,
.mde-preview .codeblock {
.tok-keyword {
color: #c678dd;
}
.tok-string {
color: #98c379;
}
}
The .tok-* classes are finer-grained than CodeMirror 5's modes, so combine
them for specificity — e.g. .tok-variable-name.tok-function for function
identifiers. Copy the full set from a reference theme as a starting point.
Use the shared color tokens (recommended)
Inkdrop ships a primitive color palette — Tailwind-style --hsl-<family>-<scale> HSL triplets — in the shared @inkdropapp/css package, loaded before your theme. Instead of hard-coding hsl(...) values, reference these tokens so your theme stays consistent with the rest of the app:
:root {
--editor-background-color: hsl(var(--hsl-white));
--editor-foreground-color: hsl(var(--hsl-slate-800));
--editor-selection-background: hsl(var(--hsl-slate-500) / 40%);
}
The full list of primitive tokens is defined in tokens.css.