UNPKG

canvas-editor-pdf

Version:
309 lines (279 loc) 17.8 kB
# Changelog ## 0.6.0 (2026-08-01) > **Migrating from 0.5.0** — four breaking changes, each detailed below: > `getValue()` returns `IEditorData` directly (drop the `.data`); > `table.overflow` now defaults to `false`; `modeRule.print.filterHideElementRow` > and a set of unused `DrawPdf` methods (`getDataURL`, the `setPaper*` / > `setPage*` reconfiguration setters, `setPrintData`, `forceUpdate`, > `getRowCount`, `getCtx`) were removed; and `element.pagingId` / `pagingIndex` > no longer exist in the data shape. ### Fixed - LaTeX no longer hangs `setValue()` in the browser. The root cause was a browser-shim regression (0.4.0, Node-support refactor): `LaTexUtils.svg()` returns an already-wrapped `data:image/svg+xml;base64,…` URL, but `svgToPngDataUrl` wrapped it a second time — the resulting `<img>` never loaded and, with no `onerror` handler, the promise never resolved, stalling any awaited caller. LaTeX rendering no longer rasterizes at all (see below), so this path is gone; the shim was also hardened (uses an already-encoded data URL as-is, rejects on image load failure) for its remaining public use via `svgString2Image`. - Nested ordered lists now number each level independently instead of running the count straight through. `getValue()` strips `listId` from a list's `valueList` items (only `listLevel` survives serialization), but `formatElementList` reused a single `listId` for the whole list, so nested items shared the parent's counter. It now assigns a distinct `listId` per `listLevel` on re-import (matching canvas-editor), so a child restarts at 1 and the parent resumes afterward. - `setValue()` no longer aborts early when a document has no header or footer. It used `return` instead of `continue` while iterating the header/main/footer zones, so a missing zone bailed out of the whole method before `setEditorData` ran, leaving the content unset. - Table row height now adapts correctly for a row-spanning cell with tall content. When regrouping cells by column, the rowspan target was compared against the column index instead of the current row index, so a tall `rowspan` cell could land in the wrong row and its height not propagate. (Ported from canvas-editor.) - A table that spans pages no longer corrupts `getValue()`. The old renderer paginated by *cloning* the table element per page (`pagingId`/`pagingIndex`) and merging the clones back on serialization; repeated (`pagingRepeat`) header rows survived the merge, so a 60-row table came back with 63 rows. Pagination is now render-only and the data layer keeps a single table. - `new DrawPdf(editor.command.getValue().options, …)` and `updateOptions(...)` no longer raise a type error. canvas-editor's option types are a separate copy — and, when consumed from the editor's own source, a different module instance — so their enum-typed fields are nominally incompatible with this lib's and no type union can bridge them. The `options` parameter now accepts a loose object at the boundary (it is normalized by `mergeOption` anyway); pass this lib's `IEditorOption` for full autocomplete. ### Added - Nested list rendering (aligned with canvas-editor): `element.listLevel` is now honored — nested markers and content indent per level, unordered bullets rotate by depth (disc → circle → square), and ordered-list numbering is tracked per `listId` so a parent list resumes its sequence after a nested child. (The editor-side indent/outdent commands were not ported — this library only renders.) ### Changed - **Table pagination reworked** (ported from canvas-editor's optimize-table- pagination change). A table crossing a page boundary is now split into per-page *fragments* at the render layer — the data layer keeps one table element — instead of being cloned into several table elements. A row taller than the remaining space is split mid-row, `pagingRepeat` header rows are re-shown on continuation pages, and row-spanning cells carry across the break. New `TablePaging` module plus fragment-aware `TableParticle` and `Position`. **Breaking (data shape):** `element.pagingId` / `pagingIndex` are gone — they described the old clone-per-page model. - LaTeX formulas now render as **vector paths** drawn straight onto the jsPDF context, instead of being rasterized to a PNG and placed as an image. Output is crisp at any zoom, the PDF is smaller, and the render path is fully synchronous (no `Image`/SVG decoding — it can never stall an awaited caller). The formula's polylines come from `LaTexUtils`; stroke color follows the element's `color`. `svgString2Image`/`platform.svgToPngDataUrl` remain exported for back-compat but are no longer used internally. - A row whose visible content is entirely hidden (`element.hide` / `control.hide` / `area.hide`) now collapses to zero height in any non-design render mode, so hidden content leaves no blank gap in the exported PDF. Empty/newline-only rows are unaffected. Previously this only happened in PRINT mode, gated behind `modeRule.print.filterHideElementRow`. - **Breaking (default change):** `table.overflow` now defaults to `false` (was `true`), matching canvas-editor. When `overflow` is false, a table wider than the content area is proportionally shrunk to fit (columns compress down to `table.defaultColMinWidth`, then stop) and its horizontal offset is reset — so wide tables no longer bleed past the page margin in the exported PDF. Set `table: { overflow: true }` to restore the old behavior. (Rendering side of canvas-editor's table-width-autofit feature; the editor-only autofit menu commands were not ported.) ### Removed - **Breaking:** the `modeRule.print.filterHideElementRow` option. Hidden-row collapsing is now unconditional in non-design modes (see above), so the flag no longer had any effect. - **Breaking:** a large dead-code cleanup dropped the unused interactive-editor layer that this PDF-only fork never exercised (cursor, mouse/keyboard events, `RangeManager`, zone, worker, previewer, table operate/tool, search, the `Control` module, shortcuts, i18n, clipboard and print helpers, and their CSS/SVG assets). Along with it, several `DrawPdf` public methods were removed: `getDataURL` (page-to-PNG export), `setPaperSize` / `setPaperDirection` / `setPaperMargin` / `setPageScale` / `setPagePixelRatio` / `setPageDevicePixel` (runtime paper/DPR reconfiguration — configure via the constructor instead), `setPrintData` / `clearPrintData`, `forceUpdate` (use `render()`), `getRowCount`, and `getCtx`. `updateOptions` was intentionally **kept**. - **Breaking:** `getValue()` now returns the `IEditorData` object directly (`{ header, main, footer, graffiti }`) instead of the `IEditorResult` wrapper (`{ version, data, options }`). Read the returned object as the data itself — `getValue().data` is no longer valid. - `getElementFont(el, scale)` was merged into `getFont(el, scale = 1)` (identical behavior). This is internal API; callers should use `getFont`. ## 0.5.0 (2026-07-09) ### Added - **Multi-column layout** via a new `column` option (`count`, `gap`, `separator`, `separatorColor`, `separatorWidth`). Content flows column-by-column and only spills to the next page once the last column fills; optional separator lines are drawn between columns. Ignored in `CONTINUITY` page mode. - **Per-page header/footer control**: `disabledPages` (page numbers on which the header/footer is hidden) and `editable` on the header/footer options, plus `inactiveAlpha`. Pages with disabled chrome reclaim the vertical space. - **Nested tables** — tables inside table cells now lay out, render and paginate correctly (cell/element/position resolved through a table path). - **Areas inside table cells** — an area's background/border/placeholder is now honored when the area lives within a `td`, positioned to the cell content box. - Control `minWidth` is now honored across line wraps (placeholder elements are inserted to fill the remaining width and restored before each relayout). - `areaHideDisabled` print-mode rule. ### Fixed - LaTeX elements clear their target rect before drawing, avoiding overdraw when a page is re-rendered. - **Text watermark rendering.** The non-repeating watermark is now centered on the page (was anchored near the bottom-left and rendered off-center), and `repeat: true` now actually tiles the text across the page (the previous code relied on a canvas pattern fill that jsPDF's `Context2d` doesn't support, so a repeating watermark drew nothing). `gap` spacing applies to the tiled layout. Image watermarks are unaffected (still single, non-repeating). - **Page number font.** The page-number renderer rewrote the font family `Microsoft YaHei``Yahei` before drawing, but fonts register with jsPDF under a lowercased id (e.g. `microsoft yahei`) and no `Yahei` exists, so CJK page numbers (e.g. `第{pageNo}页/共{pageCount}页`) fell back to a Latin font and rendered as garbage. Page numbers now resolve the font the same way body text does — lowercasing the family to match the registered id and calling `setFont` — and the text is measured with that font so centered/right alignment stays accurate. ## 0.4.2 (2026-05-27) ### Fixed - Added a `typesVersions` map for the `./node` subpath so consumers on TypeScript < 5.0 (classic `moduleResolution: "node"`, which doesn't read the `exports` `types` condition) can still resolve types for `import { DrawPdf } from 'canvas-editor-pdf/node'`. Without it, those projects hit `TS2307: Cannot find module 'canvas-editor-pdf/node'`. Modern resolution (`bundler`/`node16`/`nodenext`) keeps using the `exports` map. ## 0.4.1 (2026-05-27) ### Fixed - Widened the `@napi-rs/canvas` peer dependency range from `^0.1.0` to `^0.1.0 || ^1.0.0`. 0.4.0 only accepted the 0.1.x line, so installing alongside `@napi-rs/canvas@1.x` (the current major) failed with an `ERESOLVE` peer conflict. Verified the render pipeline works unchanged on `@napi-rs/canvas@1.0.0`. ## 0.4.0 (2026-05-27) ### Added - **Node.js support** via subpath export `canvas-editor-pdf/node`. Browser consumers continue using `import { DrawPdf } from 'canvas-editor-pdf'`; Node consumers use `import { DrawPdf } from 'canvas-editor-pdf/node'`. Same public API surface in both environments. - Internal `src/platform/` shim that swaps DOM canvas / `fetch` / `Image` for `@napi-rs/canvas` / `node:fs` / `@resvg/resvg-js` in the Node build (selected via a `vite.config.ts` `resolve.alias` regex). `DrawPdf`, `Watermark` and `ImageParticle` are the only call sites that import the shim. - `fontSource` option on `DrawPdf` constructor (`'cdn' | 'bundled' | { dir }`). Default is `'bundled'` in Node (reads `dist/font/` from the installed package) and `'cdn'` in the browser (preserves pre-0.4.0 behavior). - `@napi-rs/canvas` and `@resvg/resvg-js` declared as **optional peer deps** — browser consumers don't install them; Node consumers do. - Node smoke test at [scripts/smoke/node/run.mjs](scripts/smoke/node/run.mjs) and a paired browser smoke at [scripts/smoke/browser/](scripts/smoke/browser/). - Copy-pasteable consumer examples under [examples/](examples/) (Next.js Pages & App Router, Express, standalone script, browser client). - README sections **Node usage**, **Fonts / fontSource**, and a short **Running on a server** note. ### Changed - **TypeScript** bumped from 4.9 → 5.9 (`skipLibCheck` enabled in `tsconfig` to silence stricter type errors from `@napi-rs/canvas`'s declaration file which uses TS 5+ features). - **Vite** bumped from 2.x → 5.x. Vite 5 preserves `import.meta.url` in lib mode natively, which let me drop the `generateBundle` workaround plugin the v0.4.0 prototype needed. `src/platform/node.ts#getBundledFontPath` now reads `import.meta.url` directly. - **prismjs** bumped to `^1.30.0` (fixes CVE-2022-23647 — not on the PDF render path but worth patching while we're here). - TypeScript output now lands in `dist/types/` (browser entry types at `dist/types/index.d.ts`, Node entry at `dist/types/node.d.ts`). `vite-plugin-dts` removed in favor of a single `tsc` step. - `engines.node` raised to `>=18.0.0` (Node 18 has native `fetch` + stable `node:` imports — both required by the Node platform shim). - `import jsPDF from 'jspdf'` switched to named `import { jsPDF } from 'jspdf'` for Node ESM compatibility (jsPDF's CJS default-export shape makes the default import resolve to the namespace object, not the class). - `src/dataset/enum/{Common,Editor,Element}.ts` switched from re-exporting `@hufe921/canvas-editor`'s runtime enums to inlining them locally. Required because the Node ESM build can't introspect canvas-editor's CJS bundle. - `DrawPdf.getPagePixelRatio` falls back to `1` when `window` is undefined (Node has no `window.devicePixelRatio`). - `build.sourcemap: true` moved out of `rollupOptions.output` (deprecated in Vite 5+). ### Fixed - `window.btoa` calls in `src/utils/index.ts` and `src/core/draw/particle/latex/utils/LaTexUtils.ts` swapped for the global `btoa` (available in Node 16+ and all browsers). - `HyperlinkParticle`, `DateParticle`, `BlockParticle` constructors now skip their DOM popup/container setup when `typeof document === 'undefined'`. PDF render path never touches those nodes, so this is safe and unblocks the Node bundle. - `Watermark` no longer assumes `temporaryCanvas.style` exists (`@napi-rs/canvas` has no DOM-style accessor). ### Removed - `vite-plugin-dts` (`tsc` covers the same job and avoids dual-emission to `dist/` and `dist/types/`). - `vitepress` and `vue` from devDependencies (unused — no docs site is built from this repo). Removes 15+ transitive vulnerable packages from the install tree. ## 0.3.2 (2026-05-22) ### Changed - Upgraded **jspdf** 3.0.4 → 4.2.1. No public API changes affecting the lib's use of `Context2d`, `addImage`, `addPage` or font registration. ### Fixed - **PDF size growth on repeated export.** Reusing a `DrawPdf` instance and calling `render()` + `save()` multiple times produced increasingly large PDFs (1st ~700 KB, 2nd+ ~2 MB when images were present). Root cause: jsPDF's `putImage` splices `"FlateEncode"` out of the *live* array returned by `getFilters()`, so after the first save with an image the filter array becomes `[]` and later saves emit page content uncompressed. Fix: recreate the jsPDF instance at the start of every `render()` so each export starts from a clean filter state; fonts are cached as base64 and reapplied synchronously (no CDN refetch). Constructor now delegates jsPDF init to `_resetPdf`. - ⚠️ **Breaking for some callers:** `getPdf()` must be called **after** `render()`, since the instance reference changes each render. ## 0.3.1 (2026-05-21) ### Fixed - Build/type errors surfaced by the canvas-editor 0.9.133 sync. Build- and types-only, no behavior changes: - Replaced the `package.json` import in `DrawPdf` with a `__VERSION__` token injected via Vite `define` (the import escaped `tsconfig` `rootDir`). - Added `filterEmptyControl` / `filterHideElementRow` to the print-mode defaults (`IPrintModeRule` gained them upstream). - `Control.ts` now iterates `IEditorData` over `header`/`main`/`footer` only, skipping the new `graffiti` key whose value isn't `IElement[]`. - Lint cleanup (unused vars in `Badge.ts`, `BlockParticle.ts`). ## 0.3.0 (2026-05-21) ### Added - **Sync with canvas-editor 0.9.133** (catch-up port from 0.9.94; peer dep bumped accordingly). Render-relevant changes only — editor APIs, event handlers, search, cursor and other interactive paths are intentionally not ported since this lib only produces PDF output. Highlights: - New element types: **AREA** (content block with background/border/ placeholder + hide mode), **Badge** (page-level overlay), **Label** (inline label), **Graffiti** (freehand layer), and **image captions** (optional caption below images with `{imageNo}` token). - Render/layout fixes pulled from upstream: text ascent/descender handling, zero-width elements, punctuation/tab widths; list spacing and numbering; table colgroup/adaptive height/page-break rendering; surrounding-image scaling; area positioning; watermark layering and format tokens; print mode options. - `IElement` / `IEditorOption` gained the matching upstream fields (`hide`, `areaIndex`, `label`, `imgCaption`, `graffiti`, `badge`, …) and new enums/constants (Area, Label, Graffiti, FlexDirection, …). - `AGENTS.md` with architecture and dev-workflow guidance. - `dev` script for watch-mode library builds (`vite build --mode lib --watch`), for testing via `npm link` from a consumer without re-running build manually. ### Changed - **`DrawPdf` accepts canvas-editor types directly** (constructor + `setValue`), removing the need for `JSON.parse(JSON.stringify(...))` at the consumer boundary. Options param widened `DeepRequired<IEditorOption>``IEditorOption` (defaults filled internally by `mergeOption`); data/payload widened to a union with canvas-editor's `IEditorData`. - **`npm run build` now produces the library** (was `npm run lib`). Previously `build` produced the demo and could overwrite the library `dist/` by accident. The demo entrypoint and its scripts were inherited from upstream, never used, and have been removed entirely. - Expose the types entry in `package.json#exports`. ### Fixed - Infinite recursion when rendering `float-bottom` images. ## Earlier versions See the git history for changes prior to 0.3.0.