@aiursoft/uistack-markdown-ui
v1.2.6
Published
Shared, secure Markdown editing and reading utilities for Aiursoft applications.
Readme
@aiursoft/uistack-markdown-ui
Shared Markdown UI behavior for Aiursoft applications.
- Secure
markdown-itrendering with native HTML disabled - highlight.js 11.11.1 highlighting
- Mermaid 11 enhancement with
securityLevel: "strict" - MathJax 3 enhancement and print coordination
- Monaco-compatible paste and drag/drop image upload
- Shared Monaco editor lifecycle, shortcuts, preview, view modes and textarea fallback
Install
npm install @aiursoft/uistack-markdown-uiEditor preview
import { renderMarkdown } from "@aiursoft/uistack-markdown-ui";
preview.innerHTML = renderMarkdown(editor.getValue());The renderer supports $...$, $$...$$, \\(...\\) and \\[...\\]. Native HTML is
always escaped. A fenced mermaid block remains unhighlighted for Mermaid to process.
Complete Markdown editor
createMarkdownEditor owns the common editor behavior while the application remains
responsible for loading Monaco. Passing a loader instead of importing Monaco keeps it
out of application bundles and works with the standard Monaco AMD loader.
import { createMarkdownEditor } from "@aiursoft/uistack-markdown-ui";
const markdownEditor = await createMarkdownEditor({
editorContainer: document.querySelector("#markdown-editor"),
textarea: document.querySelector("#markdown-source"),
previewContainer: document.querySelector("#markdown-preview"),
editorPane: document.querySelector("#editor-pane"),
previewPane: document.querySelector("#preview-pane"),
form: document.querySelector("form"),
loadMonaco: () => AiursoftMarkdownUi.loadMonacoFromAmd(),
theme: "vs-dark",
uploadUrl: "/api/files/upload",
initialViewMode: "split",
viewModeStorageKey: "markdown-view-mode",
viewModeControls: [
{ element: document.querySelector("#edit-mode"), mode: "editor" },
{ element: document.querySelector("#split-mode"), mode: "split" },
{ element: document.querySelector("#preview-mode"), mode: "preview" }
],
hljs,
mermaid,
MathJax,
onSave: markdown => saveMarkdown(markdown),
onInitializationError: error => console.error("Monaco failed to initialize", error),
onPreviewError: error => console.error("Markdown preview failed", error)
});
await markdownEditor.setViewMode("preview");
markdownEditor.syncTextarea();
markdownEditor.setValue("# Updated");
markdownEditor.focus();
markdownEditor.dispose();The controller initializes Monaco for Markdown, keeps the original textarea synchronized,
debounces secure preview rendering, enhances highlight.js/Mermaid/MathJax, supports image
paste and drop, and applies consistent professional Monaco defaults (14px Cascadia Code
font stack, ligatures, semantic highlighting and comfortable vertical padding). Applications
can still override individual Monaco settings through editorOptions.
It also registers consistent Markdown shortcuts:
- Ctrl/Cmd+B: bold
- Ctrl/Cmd+I: italic
- Ctrl/Cmd+K: inline or fenced code
- Ctrl/Cmd+L: link
- Ctrl/Cmd+1 through Ctrl/Cmd+6: headings
- Ctrl/Cmd+S:
onSave - Enter: continue bullet and ordered lists
If Monaco cannot be loaded, the original textarea becomes visible and continues to drive
the same preview. Applications therefore use one fallback policy instead of implementing
their own. Preview enhancement errors are reported through onPreviewError and never
replace a working Monaco editor. onError remains as a deprecated compatibility callback
for both error categories.
Reading pages
import {
initializeMarkdownReader,
printMarkdown
} from "@aiursoft/uistack-markdown-ui";
await initializeMarkdownReader({
container: ".markdown-body",
hljs,
mermaid,
MathJax
});
printButton.addEventListener("click", () =>
printMarkdown({ container: ".markdown-body", hljs, mermaid, MathJax }));Only code blocks inside the supplied container are highlighted. Mermaid is always
initialized in strict security mode. The reader also applies the shared responsive
Bootstrap table treatment and opens rendered links with noopener noreferrer.
Image paste and drop
import { attachImageUpload } from "@aiursoft/uistack-markdown-ui";
const uploads = attachImageUpload({
editor,
eventTarget: editorContainer.parentElement,
uploadUrl: "/api/files/upload",
onError: (error, file) => console.error(`Failed to upload ${file.name}`, error)
});
// Call uploads.dispose() when the editor is destroyed.The default queue uploads three files concurrently and retries HTTP 429 responses up
to five times. Clipboard images are accepted from both clipboardData.files and
clipboardData.items, and are captured before Monaco consumes the paste event. Use
the parent of Monaco's host container as eventTarget; createMarkdownEditor() does
this automatically. Use getImageUrl when an endpoint does not return
internetPath or InternetPath.
Aiursoft application contract
MarkToHtml, MoongladeV2, EmployeeCenter and Kanban use the global IIFE build and the
same createMarkdownEditor contract. Monaco, live preview, highlight.js, Mermaid,
MathJax, Markdown shortcuts, image paste/drop, editor/split/preview modes and the
textarea fallback are required capabilities for these full editors.
DocsViewer and HowToCookViewer are reader-only consumers. Their Markdown containers
use initializeMarkdownReader for highlighting, Mermaid, MathJax, responsive tables
and safe external-link behavior.
Translate is an intentional product-level exception. It keeps its lightweight CodeMirror Markdown input because translation does not need code highlighting, Mermaid, MathJax, uploads or the full editing toolbar. It must not be treated as an incomplete migration.
