Images
The editor shows Markdown images () in place, lets the user paste or drop new ones,
and resizes them with a drag. Where image bytes come from and where they go is the host's
decision, through two EditorHost callbacks.
Showing images: resolveImage
Section titled “Showing images: resolveImage”resolveImage(src) gets the image target exactly as written and returns a URL the page may load,
or null to show the source text instead.
import { createEditorState } from "@openmarkdown-dev/editor";
const state = createEditorState({ doc, docPath: "/notes/today.md", host: { resolveImage: (src) => { if (src.startsWith("https://")) return src; return `/files/notes/${src.replace(/^\.\//, "")}`; // your server serves the document's folder }, },});-
Without
resolveImage, absolutehttps:images load, from any host, and nothing else does. The browser fetches them when the document is shown, which tells their server the document was opened. For private documents, pass aresolveImagethat allows only your own hosts, or turn remote images off entirely:createEditorState({ doc, host: { resolveImage: () => null } }); // no image loads; the source shows -
Whatever you return, script-capable URLs (
javascript:and similar) are dropped. See Untrusted content.
Pasting and dropping: saveAttachment
Section titled “Pasting and dropping: saveAttachment”When the user pastes or drops an image, the editor calls
saveAttachment(docPath, bytes, hint) with the image bytes and a file-name hint. Store the bytes
and resolve the document-relative path to link; the editor inserts an image link to that path
where the image was pasted or dropped, with the caret in its alt text.
Resolve null when the save failed; the editor inserts nothing (report the failure yourself).
import { createEditorState } from "@openmarkdown-dev/editor";
const urls = new Map<string, string>();let n = 0;
const state = createEditorState({ doc: "", docPath: "/draft.md", // paste and drop need a document path host: { saveAttachment: async (_docPath, bytes, hint) => { const name = `attachments/pasted-${++n}.png`; urls.set(name, URL.createObjectURL(new Blob([bytes.slice()], { type: "image/png" }))); return name; }, resolveImage: (src) => urls.get(src) ?? (src.startsWith("https://") ? src : null), },});This keeps images in the browser tab only. A real app uploads the bytes and returns the path or URL it stored them under.
resolveImage may be called more than once for the same image, so keep it free of side
effects. When its answer changes, for example after the reader allows remote images, call
editor.refreshImages() and every image is resolved again, including those in tables.
- Without
saveAttachment, pasting or dropping an image inserts nothing. - With
docPathset tonull(an unsaved document), there is nowhere to store beside, so the editor does not callsaveAttachment. - In both cases the editor stays silent. To tell the user, pass
onUnsupportedPaste: it is called with the reason ("no-save-attachment"or"no-doc-path") and how many images were dropped.
import { createEditorState } from "@openmarkdown-dev/editor";
const state = createEditorState({ doc, host: { onUnsupportedPaste: (reason, count) => { showToast(`${count} image(s) not added: this editor cannot store images.`); }, },});hintis the file's name, or its MIME type when it has no name. It is a hint, not a checked type: look at the bytes before you store or serve them.
Resizing
Section titled “Resizing”Every image has a grip in its corner. Dragging it resizes the image, and on release the editor
writes the width into the alt text as |W:
Only that width changes in the file. In reading mode the grip is hidden.