mirror of
https://github.com/excalidraw/excalidraw.git
synced 2026-10-19 16:15:56 +00:00
* [export] rewrite - init * restore elements + filter deleted in export API (restores #11470 behavior) * fix snaps * port export callers added on master to the new API + snaps - renderOverrides (#12100), sticky notes (#12064) and arrow-label hole (#10947) tests called the old positional exportToSvg/exportToCanvas - embedded-scene snapshots gain master's new element fields (created, baseFontSize, labelPosition); decoded payloads match master's Claude Opus 5.5 (xhigh) * restore elements in embedded scene + json clipboard export (restores #12060 behavior) - master's #12060 made every public export entry point restore its input (legacy elements reach lower-level code with `created: null`), incl. the PNG metadata embed and the json clipboard copy in the removed @excalidraw/utils wrappers - SVG embed now serializes the restored, non-deleted elements (same as master's utils path), PNG embed serializes restoreElements(data.elements) and json clipboard copies the non-deleted restored elements - port #12060's utils tests to the new API, observing renderers/serializer instead of the (now identical) scene export functions Claude Opus 5.5 (xhigh) * make config.canvasBackgroundColor the single export background knob - background resolved once in configExportDimension; exportToSvg no longer reads appState.exportBackground (now omitted from ExportSceneData's appState type), and honors `canvasBackgroundColor: false` - outline arrowheads (circle/triangle/diamond_outline, cardinality_zero_*) are filled with the resolved background color, also when the background isn't painted (as on master) — the canvas path filled them transparent, showing the arrow's shaft through them; SVG ignored the config color - JPEG: `canvasBackgroundColor: false` falls back to the default background (+ warning) instead of rendering black; no more warning for the default - callers (exportCanvas, ImageExportDialog, library/chart/publish previews, AI) pass the background via config only Claude Opus 5.5 (xhigh) * resolve export theme before creating frame labels - frame labels were colored by appState.exportWithDarkMode, ignoring config.theme (export dialog's dark toggle), and in dark exports the dark-theme label color got dark-filtered again by the renderer (#7a7a7a -> #848484) - theme is now resolved once in configExportDimension; dark labels are pre-reverted so they render with the editor's frame name color Claude Opus 5.5 (xhigh) * drop appState.exportWithDarkMode theme fallback in export - `config.theme` is the only theme input (defaults to light); the type already omitted `exportWithDarkMode` from `data.appState` - callers that relied on the fallback (PublishLibrary item preview, AI frame export) pass `theme` explicitly, keeping their behavior Claude Opus 5.5 (xhigh) * exportToClipboard: don't restore appState before exportToSvg (already restored there) Claude Opus 5.5 (xhigh) * remove unused getExportSize, type getCanvasSize's [x, y, width, height] (not Bounds) Claude Opus 5.5 (xhigh) * fix typos in export comments/JSDoc Claude Opus 5.5 (xhigh) * port with-script-in-browser example to the new export API - exportToSvg/Blob/Canvas/Clipboard take `{ data, config }`; theme via `config.theme`, padding 10 kept explicit (new default is 0) - dropped the no-op `width`/`height` appState overrides from the SVG export Claude Opus 5.5 (xhigh) * call getDimensions once, ignore it when widthOrHeight is set - with an explicit `fit: "contain"`, getDimensions ran twice (the second time on its own output); it now supplies width/height (+ scale) once, and `contain` scales the content into that frame - getDimensions + widthOrHeight both applied; widthOrHeight now wins (with a warning), like width/height/maxWidthOrHeight already did - `fit: "none"` (the E+ export server path) renders identically Claude Opus 5.5 (xhigh) * type the export size options as mutually exclusive - `width`/`height`, `maxWidthOrHeight`, `widthOrHeight` and `getDimensions` are now a union where the unused options are `?: never`, so combining them is a type error (runtime still ignores/warns for JS callers) - the `never` keys are remapped over `keyof`, so every option keeps its JSDoc in completions & hovers (verified via the TS language service) Claude Opus 5.5 (xhigh) * replace getDimensions with a `scale` function, round the canvas size - `config.scale` also accepts `(width, height) => number`, called with the export dimensions at scale 1 (padding included) — covers content-dependent scaling (e.g. E+'s pixel budgets) without the getDimensions round trip - remove `getDimensions`: its returned `scale` replaced `config.scale` and multiplied the returned size, so callers thinking in output pixels had to divide it back out - exportToCanvas rounds the canvas size instead of letting the canvas truncate it (float noise like 28.999999999999996 lost a pixel); half pixels now round up (frame label area 20.5px, mermaid preview 89.5px) Claude Opus 5.5 (xhigh) * align fit/padding/position export docs with the code - `fit` defaults to "contain" when `width`/`height` is set, otherwise "none" (the doc said the opposite); dropped the unimplemented "x/y force none" claim - padding is always subtracted for `maxWidthOrHeight`/`widthOrHeight` (they ignore `fit`), not added - `position` values are "center" | "topLeft" (doc listed "none") Claude Opus 5.5 (xhigh) * derive a missing export width/height from the aspect ratio - with `fit: "contain"` (the default when a size is given), passing only `width` or `height` now derives the other from the content's aspect ratio, as documented — it defaulted to the content's unscaled size, e.g. `{ height: 50 }` of 200x100 content gave a 200x50 canvas with 60x30 content in wide empty bands (now 80x50 with padding 10) - with `fit: "none"` the missing side stays the content extent Claude Opus 5.5 (xhigh) * default export `fit` to "none" when x/y is set - `{ x, y, width, height }` was scaled to fit with `x`/`y` silently ignored (`fit` defaulted to "contain" whenever a size was given); an explicit region now crops by default, `fit: "contain"` still opts in (and ignores `x`/`y`, as now documented) Claude Opus 5.5 (xhigh) * ignore export x/y when the content is scaled to fit - with `fit: "contain"`, `maxWidthOrHeight` or `widthOrHeight`, `x`/`y` shifted the fitted content by a mix of scene units and pixels; they're now dropped with a warning, which the previous commit already documented (its "ignored" claim was based on a coincidental probe) Claude Opus 5.5 (xhigh) * pad an export x/y region on all sides - with `position: "center"` (the default), the centering adjustment also ran on axes pinned by `x`/`y`, shifting the region by the padding: the canvas started exactly at `x`/`y` with all padding on the right/bottom (`position: "topLeft"` padded all sides); `position` now only applies to unpinned axes, as documented Claude Opus 5.5 (xhigh) * consolidate exportToCanvas/Blob/Svg into exportScene({ type, data, config }) - `type: "canvas" | "png" | "jpeg" | "svg"`, return type per `type` (overloads, plus a union overload for dynamic callers); per-type options are type-checked: `quality` only for jpeg, `embedScene` for png/svg, `renderEmbeddables`/`skipInliningFonts`/`reuseImages` for svg - the format replaces `mimeType` (and its "image/jpg" typo handling) - `appState.exportEmbedScene` -> `config.embedScene` (no longer read from `data.appState`); `data.files` is optional - `config.createCanvas` -> `config.environment.createCanvas` (where #11997's render environment and richtext's text metrics will go) - exportToCanvas/Blob/Svg are no longer exported (no aliases); exportToClipboard stays, routed through exportScene - callers, the with-script-in-browser example and tests ported Claude Opus 5.5 (xhigh) * export: take only scene settings from data.appState, frameRendering -> config.frames - `data.appState` is typed as (and stripped at runtime to) the scene settings a .excalidraw file stores; the renderer state is built from those + defaults, so editor state passed in (a live AppState: open dialog, cropping, frame highlight…) can't affect the output. It only supplies the default background and what `embedScene` embeds - `appState.frameRendering` -> `config.frames: { name, outline, clip }` - editor callers translate their export settings via one internal `getExportConfigFromAppState`; `exportCanvas` drops its redundant exportBackground/viewBackgroundColor options - fixes the editor's SVG export ignoring `exportScale` (the branch's exportCanvas SVG path had dropped it; master passed it) Claude Opus 5.5 (xhigh) * type export positioning options as width/height-only - `fit`, `position`, `x`, `y`, `origin` move into the size-option union's `width`/`height` member, so combining them with `maxWidthOrHeight` / `widthOrHeight` (which ignore them) is a type error; runtime unchanged (still ignores/warns for JS callers) - docs stay visible in completions (same `keyof` remap as the size options) Claude Opus 5.5 (xhigh) * move export `loadFonts` into `config.environment` - font loading is a host capability, next to `createCanvas` (svg gets `environment: { loadFonts }` only, as it creates no canvas) Claude Opus 5.5 (xhigh) * changelog: export API (exportScene, config, migration table) Claude Opus 5.5 (xhigh) * export: default padding back to 10, canvas at least 1px - export bounds are geometric (no stroke width), so padding 0 cut half of the strokes on the content's edge and made flat content (a line) zero-height — the library/chart/publish previews, which inherited master's default of 10, rendered blank thumbnails for lines - canvas dimensions never go below 1px (a 0-sized canvas can't be encoded); SVG snapshot sizes are back to master's Claude Opus 5.5 (xhigh) * export: clamp padding against the fitted size, before deriving from it - the padding clamp used the content's unpadded size, so flat content (a horizontal line) lost its padding with maxWidthOrHeight/widthOrHeight (`{ padding: 10, maxWidthOrHeight: 400 }` → 200x0); it now only considers the target being fitted into - a missing width/height was derived before clamping (`{ height: 10, padding: 10 }` → 0x10, SVG viewBox NaN/Infinity) - a zero-extent content axis no longer yields a NaN scale under contain Claude Opus 5.5 (xhigh) * export: clip frame exports to the frame - frame clipping was off for exportingFrame (to avoid the rounded per-element clip), relying on the canvas/SVG edge — which only crops when the export is exactly the frame; a larger export (size options) painted children and overlapping elements into the margins, and SVG frame exports had stopped clipping (master clipped them) - everything drawn is now clipped to the frame with square corners: a canvas clip after the background (`renderConfig.clipToFrame`), and an SVG group with the frame's clip path; the background isn't clipped Claude Opus 5.5 (xhigh) * changelog: fill in PR numbers for the placeholder links Claude Opus 5.5 (xhigh)