Skip to main content

PDF Template Designer

MuPdfTemplateDesigner is a React component from the @muonroi/ui-engine-pdf-designer package (v1.0.0 GA). It provides a Monaco-backed HTML editor for authoring PDF templates with built-in PROFILE-V1 lint, undo/redo history, and save/approval workflow integration.

This is a React-only component. There is no Lit web component equivalent.

Package

@muonroi/ui-engine-pdf-designer
npm install @muonroi/ui-engine-pdf-designer monaco-editor

Monaco Editor is an external peer dependency — the host application is responsible for bundling or providing it. The component dynamically imports monaco-editor at runtime.

License Gate

MuPdfTemplateDesigner is gated by the pdf.designer license capability. When the active license does not include pdf.designer, the component renders a locked stub in place of the editor. Ensure the license contains this capability before mounting the component.

See License Governance for activation and capability provisioning.

Props

PropTypeRequiredDescription
templatePdfTemplateYesThe parent template entity.
versionPdfTemplateVersionYesThe version to edit. Initial HTML content is read from version.contentJson.
readOnlybooleanNoWhen true, the Monaco editor is read-only and save/submit actions are hidden.
onSave(html: string) => Promise<void>YesCalled when the user saves. Errors thrown inside onSave are surfaced in the UI and block the save action.
onSubmitForApproval() => Promise<void>NoCalled when the user triggers a submit-for-approval action.
onCancel() => voidNoCalled when the user cancels edits.
onLintChange(violations: LintViolation[]) => voidNoCalled whenever the lint result changes. Receives the current violations array (empty array = clean).

PROFILE-V1 Lint

The component runs client-side lint on every content change. Lint results gate the save action: any error-severity violation blocks saving. warning-severity violations are shown but do not block saving.

Error (blocks save)

Rule IDTriggerReason
forbidden.tag.script<scriptForbidden element
forbidden.tag.form<formForbidden element
forbidden.tag.iframe<iframeForbidden element
forbidden.tag.svg<svgForbidden element
forbidden.tag.canvas<canvasForbidden element
forbidden.tag.video<videoForbidden element
forbidden.tag.audio<audioForbidden element
forbidden.tag.input<inputForbidden element
forbidden.tag.button<buttonForbidden element
forbidden.tag.select<selectForbidden element
forbidden.tag.textarea<textareaForbidden element
forbidden.tag.link<linkForbidden element
forbidden.link.scheme.javascripthref="javascript:Forbidden href scheme
forbidden.link.scheme.filehref="file:Forbidden href scheme
forbidden.import.external@import "https://External stylesheet import

Warning (allows save)

Rule IDTriggerReason
forbidden.display.flexdisplay: flexNot supported by PROFILE-V1 print engine (block layout only)
forbidden.display.griddisplay: gridNot supported by PROFILE-V1 print engine
forbidden.position.fixedposition: fixedNot supported by PROFILE-V1
forbidden.css-animation@keyframesAnimations not supported
forbidden.background.gradientlinear-gradient( or radial-gradient(Gradients not supported
size.html.exceeds-512kbContent > 512 KBServer will reject oversized templates

Undo/Redo

The component maintains an undo/redo stack via usePdfTemplateHistory with a capacity of 50 actions. Standard keyboard shortcuts (Ctrl+Z / Ctrl+Shift+Z) are handled by Monaco.

Usage

import { MuPdfTemplateDesigner } from "@muonroi/ui-engine-pdf-designer";
import type {
PdfTemplate,
PdfTemplateVersion,
LintViolation
} from "@muonroi/ui-engine-pdf-designer";

export function TemplatePage({
template,
version
}: {
template: PdfTemplate;
version: PdfTemplateVersion;
}) {
const handleSave = async (html: string) => {
await apiClient.updateDraft(template.id, version.versionNumber, {
contentJson: html,
contentType: "text/html",
updatedBy: currentUserId
});
};

const handleSubmit = async () => {
await apiClient.submitForApproval(template.id, version.versionNumber, {
submittedBy: currentUserId
});
};

const handleLintChange = (violations: LintViolation[]) => {
const errors = violations.filter((v) => v.severity === "error");
console.log(`${errors.length} error(s), ${violations.length - errors.length} warning(s)`);
};

return (
<MuPdfTemplateDesigner
template={template}
version={version}
onSave={handleSave}
onSubmitForApproval={handleSubmit}
onCancel={() => router.back()}
onLintChange={handleLintChange}
/>
);
}

See Also