Skip to content

feat: Excalidraw plugin and plugin API 0.28.0 docs - #19

Open
hamidfzm wants to merge 1 commit into
mainfrom
feat/excalidraw-plugin
Open

hamidfzm wants to merge 1 commit into
mainfrom
feat/excalidraw-plugin

Conversation

@hamidfzm

Copy link
Copy Markdown
Member

Summary

Adds the official Excalidraw plugin (com.glyph.excalidraw), which views and edits Excalidraw drawings, and documents the plugin API 0.28.0 addition it saves through (updateCode, hamidfzm/glyph#1000).

Closes hamidfzm/glyph#996

Status: merge after hamidfzm/glyph#1000 is in a release. Merging here publishes the plugin at once (the release job packages official plugins on push to main). The plugin declares apiVersion 0.26.0 and feature-detects updateCode, so on Glyph 0.26 and 0.27 it views drawings without the Edit button, and editing appears with 0.28.0. The API reference here already names 0.28.0, which is why waiting for that release reads best. glyph-md/plugin-template#15 carries the matching types.

Changes

  • plugins/com.glyph.excalidraw/:
    • Viewing: .excalidraw files open as the drawing (a plugin file type), ```excalidraw blocks holding scene JSON render as the drawing, and an Obsidian Excalidraw note (excalidraw-plugin in the frontmatter) shows its drawing in place of the boilerplate around it, read from its compressed-json or json block by a remark plugin. Drawings follow the light or dark theme, open in the lightbox, and renderStatic puts a light render into print, PDF, and website export. An empty block or file shows an "Empty drawing" placeholder, and invalid data an error label with the source.
    • Editing: a hover Edit button (only when the host passes updateCode) opens the Excalidraw editor in a ctx.ui.openOverlay overlay. Done saves while the editor is still open; Escape, the close button, and the window closing save from the cleanup. Saves keep the source format: pretty scene JSON, or LZ-string compressed-json chunked exactly as Obsidian writes it, and an Obsidian note changes only inside its drawing block. A refused save (the note changed or closed) keeps the editor open and turns Done into Copy and close; a refusal on the other ways out tries the clipboard and says what happened. A close without changes writes nothing.
    • Offline and contained: the editor and renderer ship as assets/excalidraw.js (4.0 MB, loaded on the first drawing through a blob URL import, like Slides loads reveal.js), built from src/ by build.mjs with esbuild. Excalidraw's fonts are inlined as data: URLs, and the 13 MB CJK font gets Excalidraw's own local: marker, so nothing falls back to its CDN; a bundle-local fetch decodes data: URLs (the app's connect-src has none) and refuses everything else. Scene files that are not data:image/ are dropped, links in the editor never navigate the window, and the rendered SVG is sanitized (anchors and foreignObject removed, images inlined in place of the <use> sanitizers drop). Mermaid-to-drawing conversion is stubbed out (about 3 MB; Glyph renders Mermaid itself), and only Glyph's five languages are bundled.
    • LICENSE is written by build.mjs from the packages esbuild put in the bundle, plus the fonts' notices (src/licenses/), so it cannot fall behind a dependency update. The build is reproducible: two runs give byte-identical assets/excalidraw.js and LICENSE.
    • plugin.json carries the placeholder sha256; the release job rewrites packageUrl and the digest.
  • index.json, index/, and docs/plugin-catalog.md regenerated with scripts/build-index.mjs.
  • docs/api-reference.md: updateCode (API 0.28), and plugin file types open in the viewer and can be saved through it.
  • docs/bundling.md: loading a large library as an asset, and bundling React only for a root of the plugin's own.

Testing

  • node --test in the plugin folder: 15 passing (Obsidian detection and the remark transform, the compressed round trip and chunking, the close-path save and its refusals, registrations and locale key parity).
  • node scripts/check-plugins.mjs, the schema validation for plugin.json and index.json, and the repo's script tests pass. A fresh scripts/build-index.mjs leaves the committed index unchanged.
  • Headless WebKit under the app's shipped CSP, loading the bundle and main.js the way the app does, with a fake plugin context: drawings, dark and light SVG, compressed drawings, embedded images, the empty and invalid states, and renderStatic; the Edit button present only with updateCode; Done after drawing a rectangle saves pretty JSON once, a close without changes saves nothing, Escape while typing a label keeps the text, and a refused save keeps the editor open with Copy and close; a scene file naming an outside URL is never requested. Zero requests left the page and no page errors were raised.
  • The host side (feat(plugins): let a fenced renderer save its block hamidfzm/glyph#1000) has its own tests for updateCode.
  • Not yet run inside a built Glyph window: the overlay's fullscreen transition, Ctrl/Cmd+Z in the note after a save, the lightbox, and print and PDF output.

com.glyph.excalidraw views and edits Excalidraw drawings: .excalidraw files, excalidraw code blocks, and Obsidian Excalidraw notes. Drawings render offline in the app theme, zoom in the lightbox, and print and export light. Edit opens the Excalidraw editor over the app and saves the drawing back in the format it came from through updateCode (plugin API 0.28.0); older apps still view drawings.

The API reference documents updateCode, and the bundling guide covers loading a large library as an asset and bundling React for a root of the plugin's own.

Closes hamidfzm/glyph#996

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an Excalidraw plugin that views and edits drawings

1 participant