본문으로 건너뛰기
cccskills
무료GitHub에 공개

block-print-system

Printing and PDF export for AI response blocks and messages via @ai-matrx/print. Use when adding a print button or BlockPrinter to a render block, wiring PrintOptionsDialog/usePrintOptions, captureBlockElement, or useDomCapturePrint, or when a print window shows no images or a print fails silently.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md8.4 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Block Print System

Three-tier architecture for printing AI response messages, plus the reusable printing core that other surfaces build on. The core lives in the @ai-matrx/print npm package (extracted 2026-08-29; source aidream/apps/shared/print) — chat-specific tiers live with the conversation feature.

Architecture Overview

Tier 1 — Quick Print (prose only)
  printMarkdownContent() → regex → HTML window
  File: ../aidream/apps/shared/chat/src/conversation/utils/markdown-print.ts
  Limitation: ignores all custom blocks

Tier 2 — Full Message (DOM screenshot)
  useDomCapturePrint → html2canvas + jsPDF
  File: ../aidream/apps/shared/chat/src/conversation/hooks/useDomCapturePrint.ts
  Hook returns: { captureRef, isCapturing, progress, captureAsPDF, error }
  isCapturing must be wired to the menu item (disabled state + label change)

Tier 3 — Per-Block (best quality, block owns its output)
  Print button in each block's header → either HTML template printer or DOM capture
  Dialog + hook: @ai-matrx/print/react (PrintOptionsDialog, usePrintOptions)

The BlockPrinter Interface

Source of truth: @ai-matrx/print/core (BlockPrinter, PrintVariant, PrintSetting, PrintSettings)

interface BlockPrinter {
    label: string;
    variants: PrintVariant[];
    settings?: PrintSetting[];
    print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
}

interface PrintVariant { id: string; label: string; description?: string; }

// PrintSetting is a discriminated union of FOUR control types (all support
// appliesTo?: string[] — which variantIds the setting shows for):
//   { type: "boolean"; id; label; description?; defaultValue }
//   { type: "range";   id; label; fromId; toId; defaultFrom; defaultTo; min?;
//     fromPlaceholder?; toPlaceholder? }   // two number inputs; writes TWO
//     settings-map keys (fromId/toId); 0 = "no bound" by convention
//   { type: "number";  id; label; defaultValue; min?; max? }  // single numeric input
//   { type: "select";  id; label; options: {value,label}[]; defaultValue }
//     // compact segmented one-of-N row

type PrintSettings = Record<string, boolean | string | number>;

If variants.length === 0 AND settings.length === 0, usePrintOptions calls print(data) immediately with no dialog. Otherwise the PrintOptionsDialog opens first (Dialog on desktop, Drawer on mobile).

Existing Printers

Block / surfaceStrategyFile
FlashcardsBlockHTML template@ai-matrx/print/flashcards (flashcardsPrinter)
MultipleChoiceQuizHTML templatecomponents/mardown-display/blocks/quiz/quiz-printer.ts
MathProblemBlockHTML templatecomponents/mardown-display/blocks/math/math-printer.ts
DiagramBlockHTML templatecomponents/mardown-display/blocks/diagram/diagram-printer.ts
PD rating reportHTML templatefeatures/legal/wc/pd-ratings/print/pd-report-printer.ts
Performance review reportHTML templatefeatures/employee-performance-reviews/review-report.ts
QR label sheetsHTML template (registry-driven grid)@ai-matrx/print/labels (qrLabelsPrinter) — Avery + roll stock QR labels; template registry, calibration page, LabelSheetPreview (in /react) + jsPDF lane
Various display blocksDOM captureinline in component via @ai-matrx/alchemy/operate/capture (captureDocumentPdf) + kit downloadFile

Adding an HTML Template Printer

  1. Create <block-name>-printer.ts alongside the component file.
  2. Import buildPrintDocument, openPrintWindow, escapeHtml, type BlockPrinter, type PrintSettings from @ai-matrx/print/core.
  3. Define variants and optional settings arrays.
  4. In print(data, variantId = "default", settings?):
    • Cast and guard: if (!typed?.items?.length) { openPrintWindow(buildPrintDocument("<p>No data.</p>", ...), "fallback"); return; }
    • Call escapeHtml() on every user string.
    • Read settings as: const show = (settings?.showX ?? false) as boolean.
  5. In the component: call usePrintOptions(printer, data) (from @ai-matrx/print/react), wire triggerPrint to a <Printer> button, render <PrintOptionsDialog> outside (not inside) the block wrapper.

Full examples in the package source (aidream/apps/shared/print/src/): flashcards.ts (variants + boolean settings + fit-text auto-shrink), labels.ts (all four setting types, inch-exact @page geometry, data-URI images).

Adding a DOM Capture Block

Required pattern — copy exactly:

const blockContentRef = useRef<HTMLDivElement>(null);
const [isPrinting, setIsPrinting] = useState(false);

const handlePrint = useCallback(async () => {
    if (!blockContentRef.current || isPrinting) return;
    setIsPrinting(true);
    try {
        const [{ captureDocumentPdf }, { downloadFile }] = await Promise.all([
            import('@ai-matrx/alchemy/operate/capture'),
            import('@ai-matrx/kit/download'),
        ]);
        downloadFile('filename.pdf', await captureDocumentPdf(blockContentRef.current, { orientation: 'portrait' }), 'application/pdf'); // or 'landscape'
    } catch (err) {
        console.error('[BlockName] Print failed:', err);
    } finally {
        setIsPrinting(false);
    }
}, [isPrinting]);

Key rules:

  • captureDocumentPdf(element, { orientation }) returns the PDF bytes (orientation: "landscape" | "portrait"); save them with kit downloadFile. App code never imports @ai-matrx/print/pdf directly (guard: pnpm check:alchemy-doors)
  • Always await it — missing await means errors are invisible silent rejections
  • Attach ref to the content container, not the whole block shell or a stats summary
  • disabled={isPrinting} on the button; show "Saving…" label while active
  • If the block has fullscreen mode, add a print button in the fullscreen header too — the regular toolbar is hidden

Wiring Tier 2 isCapturing

In the assistant-message component:

const { captureRef, isCapturing, captureAsPDF } = useDomCapturePrint();

Pass isCapturing to the message options menu as a prop. The menu item should be disabled and show "Generating PDF…" while true.

Key Utilities

All in @ai-matrx/print (/core, /pdf, /markdown, /react). Since 0.3.0 the markdown converter and the print stylesheet ship IN the package — there is no host seam, and re-adding one is the defect this repo already made three times:

  • buildPrintDocument(bodyHtml, title?, extraStyles?) → complete <!DOCTYPE html> string
  • openPrintWindow(htmlDoc, filename?) → popup window; falls back to .html download if popup blocked. The window is a fresh unauthenticated document — inline every image as a data URI, never fetch.
  • printHtmlContent(bodyHtml, title?, extraStyles?) → shorthand combo
  • markdownToPdfBlob(markdown) (/pdf) → styled multi-page PDF Blob, no arguments beyond the markdown
  • markdownToHtml / getMarkdownStylesheet / printMarkdown (/markdown) → the shipped converter, the two default stylesheets ("document" and "article"), and the one-call print window. Brand it with tokens; never fork the sheet.
  • captureDocumentPdf(el, opts) (@ai-matrx/alchemy/operate/capture) → loads print's DOM-capture engine and returns the PDF bytes
  • Fixed-geometry sheets (@page { size: …; margin: 0 }, inch-exact cells, screen-only "100% scale, no margins" banner, FIT_TEXT auto-shrink): patterns in the package's flashcards.ts (Avery 5388) and, generalized to a template registry, labels.ts

Common Bugs to Watch For

  1. Missing await on captureDocumentPdf — errors silently swallowed
  2. ref on wrong element — attach to content, not stats/header/outer shell
  3. Print button absent in fullscreen — must add to fullscreen header explicitly
  4. Missing settings param in print() — use settings?.key ?? defaultValue pattern
  5. isCapturing not wired — users get no feedback during Tier 2 PDF generation
  6. Fetched images in a print window — the window has no auth; only data URIs render

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Admin debug system wiring for the floating AdminIndicator's live debug data and Copy Full Context. Use when adding debug visibility to a route or feature, wiring useDebugContext or the debug panel, capturing console errors, or enabling the copy-context workflow for a page.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

Compact two-icon Copy / Copy-for-AI controls (components/agent-copy). Use when adding copy buttons to a row, card, list, or record; merging duplicate Copy/JSON/AI controls; continuing the copy rollout; or writing a Copy-for-AI payload. NOT for markdown content actions (use rich-document-actions).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

Disclosing a surface's existing fixed AI jobs in the shell's top Agents menu. Use when a page, panel, overlay, or window already runs a mandate behind a button, assist, automatic action, or mode; when the agent-disclosure guard names a file; or during a surface check.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

The watch-fix-rerun method for making an existing platform agent or automated process efficient and correct: baseline its ledger, run one unit yourself, fix the class behind every wasted call, rerun, record. Use when asked to improve, optimize, watch, or 'make efficient' an agent, a sandbox session, a sync job, or any recurring automated process.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

Redux state for agent execution and firing agent shortcuts. Use when editing features/agents/redux/, building agent UI, creating a conversation, touching assembleRequest or NDJSON stream state, wiring agent-state selectors, adding a per-conversation capability, or triggering a shortcut from a button, menu, or code (useShortcutTrigger, launchAgentExecution).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

The provision for a call site: the exhaustive menu of values that place in the code can realistically produce. Use before creating or fixing a mandate or agent that reasons about more than its own input, when deciding whether an agent can answer at all with what it is sent, or when its output 'looks right' but nobody checked it could be. NOT for building the agent (use create-agent).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

armanisadeghi/ai-matrx32026년 10월 20일 업데이트

armanisadeghi의 스킬 모두 보기

이 스킬의 문제 신고