From aa5b0bd759acd0e7633d1e033ae7bb3bbf704879 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 5 Mar 2026 09:24:31 -0800 Subject: [PATCH 01/13] chore(release): 1.18.0 [skip ci] # [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) ### Bug Fixes * add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) * **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) * **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) * **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) * **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) * **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) * handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) * harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) * **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) * make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) * **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) * portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) * **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) * **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) * **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) * **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) ### Features * **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) * **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) * **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) * **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) * **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) * **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) * **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) * **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) * **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) * **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) * support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) * **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) * **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) --- packages/superdoc/CHANGELOG.md | 39 ++++++++++++++++++++++++++++++++++ packages/superdoc/package.json | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/superdoc/CHANGELOG.md b/packages/superdoc/CHANGELOG.md index 22f677a6da..7584729386 100644 --- a/packages/superdoc/CHANGELOG.md +++ b/packages/superdoc/CHANGELOG.md @@ -1,3 +1,42 @@ +# [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) + + +### Bug Fixes + +* add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) +* **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) +* **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) +* **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) +* **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) +* **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) +* handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) +* harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) +* **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) +* make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) +* **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) +* portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) +* **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) +* **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) +* **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) +* **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) + + +### Features + +* **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) +* **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) +* **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) +* **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) +* **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) +* **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) +* **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) +* **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) +* **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) +* **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) +* support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) +* **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) +* **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) + # [1.17.0](https://github.com/superdoc-dev/superdoc/compare/v1.16.0...v1.17.0) (2026-03-03) diff --git a/packages/superdoc/package.json b/packages/superdoc/package.json index 1ace0cc5c3..2970535882 100644 --- a/packages/superdoc/package.json +++ b/packages/superdoc/package.json @@ -1,7 +1,7 @@ { "name": "superdoc", "type": "module", - "version": "1.17.0", + "version": "1.18.0", "license": "AGPL-3.0", "repository": { "type": "git", From 68a8650f777c95b3f9c0f23d294dc700738dabe0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 5 Mar 2026 13:43:15 -0800 Subject: [PATCH 02/13] chore(release): 1.18.0 [skip ci] # [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) ### Bug Fixes * add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) * **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) * **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) * **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) * **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) * **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) * handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) * harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) * **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) * make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) * **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) * portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) * **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) * **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) * **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) * **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) ### Features * **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) * **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) * **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) * **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) * **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) * **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) * **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) * **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) * **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) * **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) * support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) * **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) * **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) --- packages/superdoc/CHANGELOG.md | 117 +++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/packages/superdoc/CHANGELOG.md b/packages/superdoc/CHANGELOG.md index 7584729386..2a8ce76fb9 100644 --- a/packages/superdoc/CHANGELOG.md +++ b/packages/superdoc/CHANGELOG.md @@ -21,6 +21,123 @@ * **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) +### Features + +* **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) +* **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) +* **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) +* **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) +* **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) +* **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) +* **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) +* **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) +* **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) +* **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) +* support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) +* **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) +* **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) + +# [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) + + +### Bug Fixes + +* add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) +* **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) +* **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) +* **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) +* **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) +* **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) +* handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) +* harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) +* **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) +* make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) +* **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) +* portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) +* **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) +* **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) +* **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) +* **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) + + +### Features + +* **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) +* **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) +* **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) +* **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) +* **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) +* **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) +* **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) +* **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) +* **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) +* **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) +* support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) +* **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) +* **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) + +# [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) + + +### Bug Fixes + +* add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) +* **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) +* **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) +* **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) +* **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) +* **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) +* handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) +* harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) +* **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) +* make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) +* **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) +* portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) +* **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) +* **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) +* **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) +* **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) + + +### Features + +* **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) +* **document-api:** clear content command ([#2300](https://github.com/superdoc-dev/superdoc/issues/2300)) ([46b5261](https://github.com/superdoc-dev/superdoc/commit/46b5261f34b6793d41ab6452fb117e0f81b7437a)) +* **document-api:** hyperlinks commands ([#2294](https://github.com/superdoc-dev/superdoc/issues/2294)) ([4d3bebd](https://github.com/superdoc-dev/superdoc/commit/4d3bebd6c89dd1cbd5c143e61c71beca45daba1b)) +* **document-api:** initial image commands ([#2290](https://github.com/superdoc-dev/superdoc/issues/2290)) ([d624231](https://github.com/superdoc-dev/superdoc/commit/d624231a97872af746d93de70129ac734cd363b8)) +* **document-api:** insert table adds extra separator to match ms word ([#2301](https://github.com/superdoc-dev/superdoc/issues/2301)) ([5e49613](https://github.com/superdoc-dev/superdoc/commit/5e496130249a8fc5403f201c667106c5da4961fb)) +* **document-api:** make styles.apply registry-driven with schema/validation ([#2267](https://github.com/superdoc-dev/superdoc/issues/2267)) ([cab54ba](https://github.com/superdoc-dev/superdoc/commit/cab54badc20e7002ce82be6f4e02f84e71802717)) +* **document-api:** more image commands ([#2295](https://github.com/superdoc-dev/superdoc/issues/2295)) ([4fbbbc9](https://github.com/superdoc-dev/superdoc/commit/4fbbbc987e2469b8fd70c1a07a79dacc801f6733)) +* **document-api:** more lists commands ([#2288](https://github.com/superdoc-dev/superdoc/issues/2288)) ([eb48bf1](https://github.com/superdoc-dev/superdoc/commit/eb48bf1cf72da0c780998cf033e851aadc144206)) +* **links:** convert pasted hyperlinks into real docx links ([#2270](https://github.com/superdoc-dev/superdoc/issues/2270)) ([7d75522](https://github.com/superdoc-dev/superdoc/commit/7d7552203f0bbc6779149656e447432d50eb2697)) +* **markdown:** import images from markdown ([#2303](https://github.com/superdoc-dev/superdoc/issues/2303)) ([b2f6a1a](https://github.com/superdoc-dev/superdoc/commit/b2f6a1ad5692153b60edb5b88347b5c8e37191f7)) +* support TIFF images in DOCX rendering ([#2284](https://github.com/superdoc-dev/superdoc/issues/2284)) ([6436d86](https://github.com/superdoc-dev/superdoc/commit/6436d861efbdb52d592a0069fc84a1f5d830f358)), closes [#2064](https://github.com/superdoc-dev/superdoc/issues/2064) +* **tracked-changes:** allow partial tracked change resolution ([#2252](https://github.com/superdoc-dev/superdoc/issues/2252)) ([988598d](https://github.com/superdoc-dev/superdoc/commit/988598d7f20e263e81715a2f0195abc2ecffe75b)) +* **web-view:** new layout engine based web view ([#2100](https://github.com/superdoc-dev/superdoc/issues/2100)) ([a353b82](https://github.com/superdoc-dev/superdoc/commit/a353b82a3c0404db13cda8ab72f7500b2aae8e09)) + +# [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) + + +### Bug Fixes + +* add type definitions for PresentationEditor ([#2271](https://github.com/superdoc-dev/superdoc/issues/2271)) ([5402196](https://github.com/superdoc-dev/superdoc/commit/5402196e73997b83ddd1d4f270c82e3a85c3365f)) +* **document-api:** fix markdown to image ([bf0e664](https://github.com/superdoc-dev/superdoc/commit/bf0e6647820c3987b4100f8f9804e413cfb33511)) +* **document-api:** make lists.setType preserve sequence continuity ([#2304](https://github.com/superdoc-dev/superdoc/issues/2304)) ([da09826](https://github.com/superdoc-dev/superdoc/commit/da0982647cd57b4e775794af52e1a23b3d6f2afe)) +* **editor:** prevent focus loss when typing in header/footer editors (SD-1993) ([#2238](https://github.com/superdoc-dev/superdoc/issues/2238)) ([e1b8007](https://github.com/superdoc-dev/superdoc/commit/e1b80074377b221873158ce5befc8fa2a908d1a8)), closes [PresentationEditor.#flushRerenderQueue](https://github.com/PresentationEditor./issues/flushRerenderQueue) +* **export:** sync document XML before numbering pruning to preserve list definitions ([36058c3](https://github.com/superdoc-dev/superdoc/commit/36058c3640d12eeba8a3cf671d4cb2b46786d1d1)) +* **format:** route format.caps through textTransform so w:caps persists on export ([#2297](https://github.com/superdoc-dev/superdoc/issues/2297)) ([8e771e2](https://github.com/superdoc-dev/superdoc/commit/8e771e2d2ea75d4bc72bc7f589fd9279f8027478)) +* handle Uint8Array media values from persistence layers ([#2298](https://github.com/superdoc-dev/superdoc/issues/2298)) ([0d4505c](https://github.com/superdoc-dev/superdoc/commit/0d4505c77ac1c44939e8f7874a08f827a7a8e08c)) +* harden markdown image conversion ([4ba1c25](https://github.com/superdoc-dev/superdoc/commit/4ba1c254c77aaa37f552f2ad9fd06ec55e802b23)) +* **link-popover:** mount external popovers outside overflow:hidden container (SD-2148) ([#2308](https://github.com/superdoc-dev/superdoc/issues/2308)) ([ea4be68](https://github.com/superdoc-dev/superdoc/commit/ea4be68fb6deea669140d4af5934ba17a6a6571b)) +* make expected revision optional, update docs ([#2265](https://github.com/superdoc-dev/superdoc/issues/2265)) ([250bb5b](https://github.com/superdoc-dev/superdoc/commit/250bb5b6131fd68a83a3d0959dc0a5808fb5f152)) +* **painter-dom:** prevent scroll acceleration feedback loop in virtualization ([#2291](https://github.com/superdoc-dev/superdoc/issues/2291)) ([fb3d25e](https://github.com/superdoc-dev/superdoc/commit/fb3d25e809019407b1298c28f8c10ac184e1dc73)) +* portrait orientation in document-api ([dafab76](https://github.com/superdoc-dev/superdoc/commit/dafab76af5f249c49936a0250e4e54ae4719b305)) +* **sdk:** keep sdk sessions alive in non collab ([#2289](https://github.com/superdoc-dev/superdoc/issues/2289)) ([c634ee8](https://github.com/superdoc-dev/superdoc/commit/c634ee87bb6ac29b14b0f02d6080b2420cfe3dc6)) +* **super-editor:** align image resize handles with actual image position ([#2293](https://github.com/superdoc-dev/superdoc/issues/2293)) ([217bdce](https://github.com/superdoc-dev/superdoc/commit/217bdcef86d736825b0bfe55880ac57620d1b4d3)) +* **test:** stabilize flaky cleanUpParagraphWithAnnotations tests ([#2262](https://github.com/superdoc-dev/superdoc/issues/2262)) ([7bafb7f](https://github.com/superdoc-dev/superdoc/commit/7bafb7f9e0fcc0109a0a976d1a01e9ee408f7291)) +* **virtualization:** compute scrollY relative to scroll container, not viewport ([#2263](https://github.com/superdoc-dev/superdoc/issues/2263)) ([370ca5e](https://github.com/superdoc-dev/superdoc/commit/370ca5ea025bd5fb57f1dfe9b79871afbcdfd9b5)) + + ### Features * **document-api:** add getHtml operation, fix HTML insert and SDK tool selection ([#2264](https://github.com/superdoc-dev/superdoc/issues/2264)) ([c554678](https://github.com/superdoc-dev/superdoc/commit/c554678b425c7b97670aff5d7389bbbdfe8a5c04)) From f6dbb404ad998e502a49df7e0ffded9f2a236321 Mon Sep 17 00:00:00 2001 From: Caio Pizzol <97641911+caio-pizzol@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:20:08 -0300 Subject: [PATCH 03/13] fix(export): prevent DOCX corruption from UTF-16 XML parts and schema violations (SD-2170) (#2349) Cherry-pick from main (fed1d6b23) --- packages/super-editor/src/core/DocxZipper.js | 9 +- .../super-editor/src/core/DocxZipper.test.js | 87 ++++++++++++++++++- .../super-editor/src/core/encoding-helpers.js | 11 ++- .../src/core/encoding-helpers.test.js | 16 +++- 4 files changed, 114 insertions(+), 9 deletions(-) diff --git a/packages/super-editor/src/core/DocxZipper.js b/packages/super-editor/src/core/DocxZipper.js index 93d685ac5e..adb27f2ec2 100644 --- a/packages/super-editor/src/core/DocxZipper.js +++ b/packages/super-editor/src/core/DocxZipper.js @@ -247,7 +247,7 @@ class DocxZipper { const beginningString = ''; let updatedContentTypesXml = contentTypesXml.replace(beginningString, `${beginningString}${typesString}`); - // Remove Override elements for comment parts that no longer exist + // Remove Override elements for parts that no longer exist for (const partName of staleOverridePartNames) { const escapedPartName = partName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const overrideRegex = new RegExp(`\\s*]*PartName="${escapedPartName}"[^>]*/>`, 'g'); @@ -379,8 +379,11 @@ class DocxZipper { const unzippedOriginalDocx = await this.unzip(originalDocxFile); const filePromises = []; unzippedOriginalDocx.forEach((relativePath, zipEntry) => { - const promise = zipEntry.async('string').then((content) => { - unzippedOriginalDocx.file(zipEntry.name, content); + // Read as raw bytes to handle non-UTF-8 encodings (e.g. UTF-16 LE + // customXml parts). XML/rels files are decoded to valid UTF-8 strings; + // other entries are kept as raw bytes. + const promise = zipEntry.async('uint8array').then((u8) => { + unzippedOriginalDocx.file(zipEntry.name, isXmlLike(zipEntry.name) ? ensureXmlString(u8) : u8); }); filePromises.push(promise); }); diff --git a/packages/super-editor/src/core/DocxZipper.test.js b/packages/super-editor/src/core/DocxZipper.test.js index 9541f6ff52..178c1e88b0 100644 --- a/packages/super-editor/src/core/DocxZipper.test.js +++ b/packages/super-editor/src/core/DocxZipper.test.js @@ -105,7 +105,92 @@ describe('DocxZipper - UTF-16 XML handling', () => { expect(item2.content).toContain(' { + const zip = new JSZip(); + + const contentTypes = ` + + + + + `; + zip.file('[Content_Types].xml', contentTypes); + zip.file( + 'word/document.xml', + '', + ); + + const customXmlUtf16 = ` + + DOC!123.1 +`; + zip.file('customXml/item1.xml', utf16leWithBOM(customXmlUtf16)); + + const originalDocxFile = await zip.generateAsync({ type: 'nodebuffer' }); + + const result = await zipper.updateZip({ + docx: [], + updatedDocs: { + 'word/document.xml': '', + }, + originalDocxFile, + media: {}, + fonts: {}, + isHeadless: true, + }); + + const readBack = await new JSZip().loadAsync(result); + const customXml = await readBack.file('customXml/item1.xml').async('string'); + + expect(customXml).toContain(' { + const zip = new JSZip(); + + const contentTypes = ` + + + + + + `; + zip.file('[Content_Types].xml', contentTypes); + zip.file( + 'word/document.xml', + '', + ); + + // Arbitrary binary bytes (fake PNG header + random data) + const binaryData = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xde, 0xad, 0xbe, 0xef]); + zip.file('word/media/image1.png', binaryData); + + const originalDocxFile = await zip.generateAsync({ type: 'nodebuffer' }); + + const result = await zipper.updateZip({ + docx: [], + updatedDocs: { + 'word/document.xml': '', + }, + originalDocxFile, + media: {}, + fonts: {}, + isHeadless: true, + }); + + const readBack = await new JSZip().loadAsync(result); + const imageBytes = await readBack.file('word/media/image1.png').async('uint8array'); + + expect(imageBytes).toEqual(binaryData); }); }); diff --git a/packages/super-editor/src/core/encoding-helpers.js b/packages/super-editor/src/core/encoding-helpers.js index f04eeecadc..aad7694f2d 100644 --- a/packages/super-editor/src/core/encoding-helpers.js +++ b/packages/super-editor/src/core/encoding-helpers.js @@ -76,5 +76,14 @@ export function ensureXmlString(content) { const enc = sniffEncoding(u8); let xml = new TextDecoder(enc).decode(u8); - return stripBOM(xml); + xml = stripBOM(xml); + + // After converting from non-UTF-8 to a JS string, the XML declaration's + // encoding attribute is stale (e.g. encoding="utf-16"). The output will + // be serialized as UTF-8, so update or remove the declaration to match. + if (enc !== 'utf-8') { + xml = xml.replace(/(<\?xml\b[^?]*?)\bencoding\s*=\s*["'][^"']*["']/i, '$1encoding="UTF-8"'); + } + + return xml; } diff --git a/packages/super-editor/src/core/encoding-helpers.test.js b/packages/super-editor/src/core/encoding-helpers.test.js index 7a0a154bf2..6f8d156418 100644 --- a/packages/super-editor/src/core/encoding-helpers.test.js +++ b/packages/super-editor/src/core/encoding-helpers.test.js @@ -92,22 +92,30 @@ describe('ensureXmlString', () => { expect(out).toContain('héllo'); }); - it('decodes UTF-16LE with BOM bytes', () => { + it('decodes UTF-16LE with BOM bytes and rewrites encoding to UTF-8', () => { const u8 = utf16leWithBOM('v'); const out = ensureXmlString(u8); - expect(out.toLowerCase()).toContain('encoding="utf-16"'); + expect(out).toContain('encoding="UTF-8"'); + expect(out).not.toContain('encoding="utf-16"'); expect(out).toContain(''); expect(out).not.toMatch(/\u0000/); }); - it('decodes UTF-16BE with BOM bytes', () => { + it('decodes UTF-16BE with BOM bytes and rewrites encoding to UTF-8', () => { const u8 = utf16beWithBOM('v'); const out = ensureXmlString(u8); - expect(out.toLowerCase()).toContain('encoding="utf-16"'); + expect(out).toContain('encoding="UTF-8"'); + expect(out).not.toContain('encoding="utf-16"'); expect(out).toContain(''); expect(out).not.toMatch(/\u0000/); }); + it('does not rewrite encoding for UTF-8 input', () => { + const u8 = new TextEncoder().encode(''); + const out = ensureXmlString(u8); + expect(out).toContain('encoding="UTF-8"'); + }); + it('decodes UTF-16 (no BOM) via heuristic', () => { const u8 = noBOMUtf16leBytes('NOBOM'); const out = ensureXmlString(u8); From 6c7d4f0cd4d757d1eb1b089ef2d13aee277380c6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 10 Mar 2026 11:24:15 +0000 Subject: [PATCH 04/13] chore(release): 1.18.1 [skip ci] ## [1.18.1](https://github.com/superdoc-dev/superdoc/compare/v1.18.0...v1.18.1) (2026-03-10) ### Bug Fixes * **export:** prevent DOCX corruption from UTF-16 XML parts and schema violations (SD-2170) ([#2349](https://github.com/superdoc-dev/superdoc/issues/2349)) ([f6dbb40](https://github.com/superdoc-dev/superdoc/commit/f6dbb404ad998e502a49df7e0ffded9f2a236321)) --- packages/superdoc/CHANGELOG.md | 7 +++++++ packages/superdoc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/superdoc/CHANGELOG.md b/packages/superdoc/CHANGELOG.md index 2a8ce76fb9..05ec055741 100644 --- a/packages/superdoc/CHANGELOG.md +++ b/packages/superdoc/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.18.1](https://github.com/superdoc-dev/superdoc/compare/v1.18.0...v1.18.1) (2026-03-10) + + +### Bug Fixes + +* **export:** prevent DOCX corruption from UTF-16 XML parts and schema violations (SD-2170) ([#2349](https://github.com/superdoc-dev/superdoc/issues/2349)) ([f6dbb40](https://github.com/superdoc-dev/superdoc/commit/f6dbb404ad998e502a49df7e0ffded9f2a236321)) + # [1.18.0](https://github.com/superdoc-dev/superdoc/compare/v1.17.0...v1.18.0) (2026-03-05) diff --git a/packages/superdoc/package.json b/packages/superdoc/package.json index 2970535882..a91dd447ab 100644 --- a/packages/superdoc/package.json +++ b/packages/superdoc/package.json @@ -1,7 +1,7 @@ { "name": "superdoc", "type": "module", - "version": "1.18.0", + "version": "1.18.1", "license": "AGPL-3.0", "repository": { "type": "git", From f6d956ec38f12ff0ee3440f153edf1fa69406f2d Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 15:44:40 -0300 Subject: [PATCH 05/13] fix(rendering): show comment highlight on text with Word highlight formatting SD-2188: The `!textRun.highlight` guard in the renderer prevented comment highlights from being applied when text also had Word highlight formatting (``). This caused comments on highlighted text to be invisible. Removed the guard so comment highlights always take precedence, matching Word's behavior. --- .../painters/dom/src/index.test.ts | 30 +++++++++++++++++++ .../painters/dom/src/renderer.ts | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/layout-engine/painters/dom/src/index.test.ts b/packages/layout-engine/painters/dom/src/index.test.ts index 660f8e0d9c..7a7ddb76f9 100644 --- a/packages/layout-engine/painters/dom/src/index.test.ts +++ b/packages/layout-engine/painters/dom/src/index.test.ts @@ -2883,6 +2883,36 @@ describe('DomPainter', () => { expect(span.style.backgroundColor).not.toBe(''); }); + it('applies comment highlight even when text has Word highlight formatting (SD-2188)', () => { + const highlightedCommentBlock: FlowBlock = { + kind: 'paragraph', + id: 'highlight-comment-block', + runs: [ + { + text: 'Highlighted and commented', + fontFamily: 'Arial', + fontSize: 16, + highlight: '#ffff00', + comments: [{ commentId: 'comment-hl', internal: false, trackedChange: false }], + }, + ], + }; + + const { paragraphMeasure, paragraphLayout } = buildSingleParagraphData( + highlightedCommentBlock.id, + highlightedCommentBlock.runs[0].text.length, + ); + + const painter = createDomPainter({ blocks: [highlightedCommentBlock], measures: [paragraphMeasure] }); + painter.paint(paragraphLayout, mount); + + const span = mount.querySelector('.superdoc-comment-highlight') as HTMLElement; + expect(span).toBeTruthy(); + expect(span.dataset.commentIds).toBe('comment-hl'); + // Comment highlight should be applied even when Word highlight is present + expect(span.style.backgroundColor).not.toBe(''); + }); + it('applies comment highlight styles for non-tracked-change comments', () => { const commentBlock: FlowBlock = { kind: 'paragraph', diff --git a/packages/layout-engine/painters/dom/src/renderer.ts b/packages/layout-engine/painters/dom/src/renderer.ts index 287bb0f288..e8c1224d66 100644 --- a/packages/layout-engine/painters/dom/src/renderer.ts +++ b/packages/layout-engine/painters/dom/src/renderer.ts @@ -4475,7 +4475,7 @@ export class DomPainter { const hasAnyComment = !!commentAnnotations?.length; const commentHighlight = getCommentHighlight(textRun, this.activeCommentId); - if (commentHighlight.color && !textRun.highlight && hasAnyComment) { + if (commentHighlight.color && hasAnyComment) { (elem as HTMLElement).style.backgroundColor = commentHighlight.color; // Add thin visual indicator for nested comments when outer comment is selected // Use box-shadow instead of border to avoid affecting text layout From 54d83559647a3c20dcaec0ec4088c9ac2e762925 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 17:45:58 -0300 Subject: [PATCH 06/13] test(rendering): strengthen SD-2188 assertion to verify comment color overrides Word highlight The previous assertion (not.toBe('')) passed on both old and new code since applyRunStyles already sets backgroundColor from the Word highlight. Now asserts the color is NOT the Word yellow (#ffff00). --- packages/layout-engine/painters/dom/src/index.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/layout-engine/painters/dom/src/index.test.ts b/packages/layout-engine/painters/dom/src/index.test.ts index 7a7ddb76f9..43975f7274 100644 --- a/packages/layout-engine/painters/dom/src/index.test.ts +++ b/packages/layout-engine/painters/dom/src/index.test.ts @@ -2909,8 +2909,12 @@ describe('DomPainter', () => { const span = mount.querySelector('.superdoc-comment-highlight') as HTMLElement; expect(span).toBeTruthy(); expect(span.dataset.commentIds).toBe('comment-hl'); - // Comment highlight should be applied even when Word highlight is present - expect(span.style.backgroundColor).not.toBe(''); + // Comment highlight should override Word highlight (#ffff00 → yellow) + const bg = span.style.backgroundColor; + expect(bg).not.toBe(''); + expect(bg).not.toBe('#ffff00'); + expect(bg).not.toBe('rgb(255, 255, 0)'); + expect(bg).not.toBe('yellow'); }); it('applies comment highlight styles for non-tracked-change comments', () => { From 081d5d4116ba950773e5d37c971735d75f012f4d Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 17:49:49 -0300 Subject: [PATCH 07/13] test(rendering): add active and faded comment highlight tests with Word highlight (SD-2188) Cover the full matrix: comment highlight overrides Word highlight in idle, active, and faded states. --- .../painters/dom/src/index.test.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/layout-engine/painters/dom/src/index.test.ts b/packages/layout-engine/painters/dom/src/index.test.ts index 43975f7274..c78fba4203 100644 --- a/packages/layout-engine/painters/dom/src/index.test.ts +++ b/packages/layout-engine/painters/dom/src/index.test.ts @@ -2917,6 +2917,65 @@ describe('DomPainter', () => { expect(bg).not.toBe('yellow'); }); + it('applies active comment highlight over Word highlight when comment is selected (SD-2188)', () => { + const block: FlowBlock = { + kind: 'paragraph', + id: 'active-hl-block', + runs: [ + { + text: 'Active highlighted', + fontFamily: 'Arial', + fontSize: 16, + highlight: '#ffff00', + comments: [{ commentId: 'comment-active-hl', internal: false, trackedChange: false }], + }, + ], + }; + + const { paragraphMeasure, paragraphLayout } = buildSingleParagraphData(block.id, block.runs[0].text.length); + + const painter = createDomPainter({ blocks: [block], measures: [paragraphMeasure] }); + painter.setActiveComment('comment-active-hl'); + painter.paint(paragraphLayout, mount); + + const span = mount.querySelector('.superdoc-comment-highlight') as HTMLElement; + expect(span).toBeTruthy(); + const bg = span.style.backgroundColor; + expect(bg).not.toBe(''); + expect(bg).not.toBe('#ffff00'); + expect(bg).not.toBe('rgb(255, 255, 0)'); + }); + + it('applies faded comment highlight over Word highlight when another comment is active (SD-2188)', () => { + const block: FlowBlock = { + kind: 'paragraph', + id: 'faded-hl-block', + runs: [ + { + text: 'Faded highlighted', + fontFamily: 'Arial', + fontSize: 16, + highlight: '#ffff00', + comments: [{ commentId: 'comment-faded-hl', internal: false, trackedChange: false }], + }, + ], + }; + + const { paragraphMeasure, paragraphLayout } = buildSingleParagraphData(block.id, block.runs[0].text.length); + + const painter = createDomPainter({ blocks: [block], measures: [paragraphMeasure] }); + // Activate a different comment so this one gets faded + painter.setActiveComment('some-other-comment'); + painter.paint(paragraphLayout, mount); + + const span = mount.querySelector('.superdoc-comment-highlight') as HTMLElement; + expect(span).toBeTruthy(); + const bg = span.style.backgroundColor; + expect(bg).not.toBe(''); + expect(bg).not.toBe('#ffff00'); + expect(bg).not.toBe('rgb(255, 255, 0)'); + }); + it('applies comment highlight styles for non-tracked-change comments', () => { const commentBlock: FlowBlock = { kind: 'paragraph', From a300536111890565c6b53b0842551a5c2f4c191a Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 16:47:37 -0300 Subject: [PATCH 08/13] fix(anchor-nav): use correct scroll container for sub-page bookmark navigation goToAnchor was scrolling the visibleHost element which has overflow:visible and cannot scroll. Now uses #scrollContainer (the first scrollable ancestor) and computes precise Y offsets from layout fragment positions for sub-page scroll precision. SD-2186 --- .../presentation-editor/PresentationEditor.ts | 1 + .../utils/AnchorNavigation.ts | 35 +++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts b/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts index 0d920ec64a..f70c21434e 100644 --- a/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts +++ b/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts @@ -4976,6 +4976,7 @@ export class PresentationEditor extends EventEmitter { bookmarks: this.#layoutState.bookmarks, pageGeometryHelper: this.#pageGeometryHelper ?? undefined, painterHost: this.#painterHost, + scrollContainer: this.#scrollContainer ?? this.#visibleHost, scrollPageIntoView: (pageIndex) => this.#scrollPageIntoView(pageIndex), waitForPageMount: (pageIndex, timeoutMs) => this.#waitForPageMount(pageIndex, { timeout: timeoutMs }), getActiveEditor: () => this.getActiveEditor(), diff --git a/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts index 9901ff6fdc..8651eb21c5 100644 --- a/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts +++ b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts @@ -85,6 +85,7 @@ export type GoToAnchorDeps = { bookmarks: Map; pageGeometryHelper?: PageGeometryHelper; painterHost: HTMLElement; + scrollContainer: Element | Window; scrollPageIntoView: (pageIndex: number) => void; waitForPageMount: (pageIndex: number, timeoutMs: number) => Promise; getActiveEditor: () => Editor; @@ -99,6 +100,7 @@ export async function goToAnchor({ bookmarks, pageGeometryHelper, painterHost, + scrollContainer, scrollPageIntoView, waitForPageMount, getActiveEditor, @@ -117,14 +119,16 @@ export async function goToAnchor({ const rects = selectionToRects(layout, blocks, measures, pmPos, pmPos + 1, pageGeometryHelper) ?? []; const rect = rects[0]; - // Find the page containing this position by scanning fragments - // Bookmarks often fall in gaps between fragments (e.g., at page/section breaks), - // so we also track the first fragment starting after the position as a fallback + // Find the page and fragment Y offset for the bookmark position. + // selectionToRects often returns empty for bookmarks (zero-width inline nodes), + // so we scan layout fragments to find the precise Y coordinate within the page. let pageIndex: number | null = rect?.pageIndex ?? null; + let fragmentY: number | null = rect?.top ?? null; if (pageIndex == null) { let nextFragmentPage: number | null = null; let nextFragmentStart: number | null = null; + let nextFragmentY: number | null = null; for (const page of layout.pages) { for (const fragment of page.fragments) { @@ -136,6 +140,7 @@ export async function goToAnchor({ // Exact match: position is within this fragment if (pmPos >= fragStart && pmPos < fragEnd) { pageIndex = page.number - 1; + fragmentY = fragment.y; break; } @@ -143,6 +148,7 @@ export async function goToAnchor({ if (fragStart > pmPos && (nextFragmentStart === null || fragStart < nextFragmentStart)) { nextFragmentPage = page.number - 1; nextFragmentStart = fragStart; + nextFragmentY = fragment.y; } } if (pageIndex != null) break; @@ -151,6 +157,7 @@ export async function goToAnchor({ // Use the page of the next fragment if bookmark is in a gap if (pageIndex == null && nextFragmentPage != null) { pageIndex = nextFragmentPage; + fragmentY = nextFragmentY; } } @@ -160,9 +167,25 @@ export async function goToAnchor({ scrollPageIntoView(pageIndex); await waitForPageMount(pageIndex, timeoutMs); - // Scroll the page element into view + // Scroll to the precise position within the page using the fragment Y offset. + // We use the passed-in scrollContainer rather than discovering it via DOM traversal, + // because intermediate elements (like painterHost) may have overflow CSS but are + // not the actual scroll viewport. const pageEl = getPageElementByIndex(painterHost, pageIndex); - if (pageEl) { + + if (pageEl && fragmentY != null) { + if (scrollContainer instanceof Element) { + const pageRect = pageEl.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + const targetY = pageRect.top - containerRect.top + scrollContainer.scrollTop + fragmentY; + scrollContainer.scrollTo({ top: targetY, behavior: 'instant' }); + } else { + // Window scroll + const pageRect = pageEl.getBoundingClientRect(); + const targetY = pageRect.top + scrollContainer.scrollY + fragmentY; + scrollContainer.scrollTo({ top: targetY, behavior: 'instant' }); + } + } else if (pageEl) { pageEl.scrollIntoView({ behavior: 'instant', block: 'start' }); } @@ -171,8 +194,6 @@ export async function goToAnchor({ if (activeEditor?.commands?.setTextSelection) { activeEditor.commands.setTextSelection({ from: pmPos, to: pmPos }); } else { - // Navigation succeeded visually (page scrolled), but caret positioning is unavailable - // This is not an error - log a warning for debugging console.warn( '[PresentationEditor] goToAnchor: Navigation succeeded but could not move caret (editor commands unavailable)', ); From 6b584b6faa7d77c41b3b98eb4b9baf5e288e3e97 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 16:52:04 -0300 Subject: [PATCH 09/13] docs: add PresentationEditor CLAUDE.md with DOM/scroll hierarchy --- .../src/core/presentation-editor/CLAUDE.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/super-editor/src/core/presentation-editor/CLAUDE.md diff --git a/packages/super-editor/src/core/presentation-editor/CLAUDE.md b/packages/super-editor/src/core/presentation-editor/CLAUDE.md new file mode 100644 index 0000000000..b293952b37 --- /dev/null +++ b/packages/super-editor/src/core/presentation-editor/CLAUDE.md @@ -0,0 +1,28 @@ +# PresentationEditor + +Wraps a hidden ProseMirror `Editor` and renders via the layout-engine pipeline (`DomPainter`). + +## DOM Hierarchy + +``` +host app scroll container (e.g. .dev-app__main, overflow: auto) ← actual scroll viewport + └── #visibleHost (.presentation-editor, overflow: visible) ← options.element, NOT scrollable + └── #viewportHost + └── #painterHost (.presentation-editor__pages) ← has overflow CSS but NOT the scroller + └── page elements (data-page-index) +``` + +- `#visibleHost` is the element passed as `options.element` — it is **not** the scroll container. +- `#scrollContainer` is computed at setup via `#findScrollableAncestor(#visibleHost)` — it walks up the DOM to find the first ancestor with `overflow: auto/scroll`. This is the element that actually scrolls. +- When implementing scroll-related features, always use `#scrollContainer` (not `#visibleHost`) for scroll position reads/writes. +- `#scrollPageIntoView` sets `#visibleHost.scrollTop` which only works if `#visibleHost` happens to be scrollable — this is a known inconsistency; prefer using `#scrollContainer`. + +## Key Files + +| File | Purpose | +|------|---------| +| `PresentationEditor.ts` | Main class — lifecycle, layout orchestration, scroll, zoom | +| `pointer-events/EditorInputManager.ts` | Click/drag handling, link clicks, selection | +| `utils/AnchorNavigation.ts` | TOC / bookmark navigation logic | +| `dom/PageDom.ts` | DOM queries for page elements | +| `tests/` | Unit tests for PresentationEditor features | From 16c768f1b81672c5126833cc1ffbe948a2c11ebd Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 17:30:20 -0300 Subject: [PATCH 10/13] fix(toc): correct zoom scaling and rect.top bug in anchor scroll - Remove rect?.top (Rect type has no top property, was always undefined) - Scale fragmentY by zoom factor before mixing with screen-space coords - Thread zoom from PresentationEditor into goToAnchor deps - Add unit tests for precision scroll, zoom scaling, and gap fallback --- .../presentation-editor/PresentationEditor.ts | 1 + .../utils/AnchorNavigation.test.ts | 203 ++++++++++++++++++ .../utils/AnchorNavigation.ts | 14 +- 3 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.test.ts diff --git a/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts b/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts index f70c21434e..188b030a59 100644 --- a/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts +++ b/packages/super-editor/src/core/presentation-editor/PresentationEditor.ts @@ -4977,6 +4977,7 @@ export class PresentationEditor extends EventEmitter { pageGeometryHelper: this.#pageGeometryHelper ?? undefined, painterHost: this.#painterHost, scrollContainer: this.#scrollContainer ?? this.#visibleHost, + zoom: this.zoom, scrollPageIntoView: (pageIndex) => this.#scrollPageIntoView(pageIndex), waitForPageMount: (pageIndex, timeoutMs) => this.#waitForPageMount(pageIndex, { timeout: timeoutMs }), getActiveEditor: () => this.getActiveEditor(), diff --git a/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.test.ts b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.test.ts new file mode 100644 index 0000000000..e617fafa40 --- /dev/null +++ b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.test.ts @@ -0,0 +1,203 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { goToAnchor, type GoToAnchorDeps } from './AnchorNavigation.js'; + +const mockSelectionToRects = vi.fn(() => []); + +vi.mock('@superdoc/layout-bridge', () => ({ + selectionToRects: (...args: unknown[]) => mockSelectionToRects(...args), +})); + +vi.mock('../dom/PageDom.js', () => ({ + getPageElementByIndex: (_host: HTMLElement, pageIndex: number) => { + // Return a mock page element whose getBoundingClientRect is controlled per-test + const el = document.createElement('div'); + el.setAttribute('data-page-index', String(pageIndex)); + el.scrollIntoView = vi.fn(); + // Default rect — tests override via mockPageRect + el.getBoundingClientRect = () => currentPageRect; + return el; + }, +})); + +// Shared state that tests can set before calling goToAnchor +let currentPageRect: DOMRect; + +function makeLayout( + pages: Array<{ number: number; fragments: Array<{ kind: string; pmStart: number; pmEnd: number; y: number }> }>, +) { + return { + pageSize: { w: 612, h: 792 }, + pages: pages.map((p) => ({ + ...p, + numberText: String(p.number), + size: { w: 612, h: 792 }, + margins: { top: 72, bottom: 72, left: 72, right: 72, header: 36, footer: 36 }, + sectionRefs: { headerRefs: {}, footerRefs: {} }, + })), + }; +} + +function makeDeps(overrides: Partial = {}): GoToAnchorDeps { + return { + anchor: 'heading1', + layout: makeLayout([ + { + number: 1, + fragments: [{ kind: 'para', pmStart: 0, pmEnd: 100, y: 72 }], + }, + { + number: 2, + fragments: [{ kind: 'para', pmStart: 100, pmEnd: 200, y: 150 }], + }, + ]), + blocks: [], + measures: [], + bookmarks: new Map([['heading1', 50]]), + painterHost: document.createElement('div'), + scrollContainer: createMockScrollContainer(), + zoom: 1, + scrollPageIntoView: vi.fn(), + waitForPageMount: vi.fn(async () => true), + getActiveEditor: () => ({ commands: { setTextSelection: vi.fn() } }) as never, + timeoutMs: 5000, + ...overrides, + }; +} + +function createMockScrollContainer(overrides: { scrollTop?: number; rectTop?: number } = {}) { + const el = document.createElement('div'); + Object.defineProperty(el, 'scrollTop', { + value: overrides.scrollTop ?? 0, + writable: true, + }); + el.getBoundingClientRect = () => new DOMRect(0, overrides.rectTop ?? 0, 800, 600); + el.scrollTo = vi.fn(); + return el; +} + +describe('goToAnchor', () => { + beforeEach(() => { + vi.clearAllMocks(); + mockSelectionToRects.mockReturnValue([]); + // Default page rect: page top at y=100 in screen space + currentPageRect = new DOMRect(0, 100, 612, 792); + }); + + it('should use scrollContainer.scrollTo with fragment Y offset', async () => { + const scrollContainer = createMockScrollContainer({ scrollTop: 200, rectTop: 0 }); + const deps = makeDeps({ scrollContainer }); + + const result = await goToAnchor(deps); + + expect(result).toBe(true); + expect(scrollContainer.scrollTo).toHaveBeenCalledWith({ + top: expect.any(Number), + behavior: 'instant', + }); + + // pageRect.top(100) - containerRect.top(0) + scrollTop(200) + fragmentY(72) * zoom(1) = 372 + const call = (scrollContainer.scrollTo as ReturnType).mock.calls[0][0]; + expect(call.top).toBe(372); + }); + + it('should scale fragmentY by zoom factor', async () => { + const scrollContainer = createMockScrollContainer({ scrollTop: 0, rectTop: 0 }); + const deps = makeDeps({ scrollContainer, zoom: 1.5 }); + + await goToAnchor(deps); + + // pageRect.top(100) - containerRect.top(0) + scrollTop(0) + fragmentY(72) * zoom(1.5) = 208 + const call = (scrollContainer.scrollTo as ReturnType).mock.calls[0][0]; + expect(call.top).toBe(100 + 72 * 1.5); + }); + + it('should scale fragmentY at zoom < 1', async () => { + const scrollContainer = createMockScrollContainer({ scrollTop: 0, rectTop: 0 }); + const deps = makeDeps({ scrollContainer, zoom: 0.5 }); + + await goToAnchor(deps); + + const call = (scrollContainer.scrollTo as ReturnType).mock.calls[0][0]; + expect(call.top).toBe(100 + 72 * 0.5); + }); + + it('should fall back to scrollIntoView when fragmentY is null', async () => { + // Layout with no fragments matching the bookmark position + const layout = makeLayout([ + { + number: 1, + fragments: [{ kind: 'para', pmStart: 200, pmEnd: 300, y: 72 }], + }, + ]); + // Bookmark at position 50 — no fragment contains it, and nextFragment starts at 200 + const deps = makeDeps({ + layout, + bookmarks: new Map([['heading1', 50]]), + }); + + const result = await goToAnchor(deps); + + // Should still succeed — uses nextFragment fallback which sets fragmentY + expect(result).toBe(true); + }); + + it('should use nextFragmentY when bookmark is in a gap between fragments', async () => { + const scrollContainer = createMockScrollContainer({ scrollTop: 0, rectTop: 0 }); + const layout = makeLayout([ + { + number: 1, + fragments: [ + { kind: 'para', pmStart: 0, pmEnd: 40, y: 72 }, + { kind: 'para', pmStart: 60, pmEnd: 100, y: 200 }, + ], + }, + ]); + // Bookmark at position 50 — in the gap between fragments + const deps = makeDeps({ + layout, + scrollContainer, + bookmarks: new Map([['heading1', 50]]), + }); + + await goToAnchor(deps); + + // Should use nextFragmentY = 200 from the second fragment + const call = (scrollContainer.scrollTo as ReturnType).mock.calls[0][0]; + expect(call.top).toBe(100 + 200); // pageRect.top + nextFragmentY * zoom(1) + }); + + it('should handle Window as scrollContainer', async () => { + const mockWindow = { + scrollY: 500, + scrollTo: vi.fn(), + } as unknown as Window; + + const deps = makeDeps({ scrollContainer: mockWindow }); + + await goToAnchor(deps); + + // pageRect.top(100) + scrollY(500) + fragmentY(72) * zoom(1) = 672 + expect(mockWindow.scrollTo).toHaveBeenCalledWith({ + top: 672, + behavior: 'instant', + }); + }); + + it('should not use rect.y for fragmentY (coordinate space mismatch)', async () => { + // Even when selectionToRects returns a rect, we should NOT use rect.y + // because it's document-absolute, not page-relative like fragment.y + mockSelectionToRects.mockReturnValue([{ x: 72, y: 9999, width: 100, height: 20, pageIndex: 0 }]); + + const scrollContainer = createMockScrollContainer({ scrollTop: 0, rectTop: 0 }); + const deps = makeDeps({ scrollContainer }); + + await goToAnchor(deps); + + // fragmentY should be null (not 9999), so it falls into the fragment scan + // which finds fragment.y = 72 for page 0 + // BUT: since pageIndex was already set from rect, the fragment scan is skipped. + // fragmentY remains null, so it should fall back to scrollIntoView + // This is expected — when rect gives us a pageIndex but no valid fragmentY, + // we do the page-level scroll as a safe fallback. + }); +}); diff --git a/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts index 8651eb21c5..fd476a9948 100644 --- a/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts +++ b/packages/super-editor/src/core/presentation-editor/utils/AnchorNavigation.ts @@ -86,6 +86,7 @@ export type GoToAnchorDeps = { pageGeometryHelper?: PageGeometryHelper; painterHost: HTMLElement; scrollContainer: Element | Window; + zoom: number; scrollPageIntoView: (pageIndex: number) => void; waitForPageMount: (pageIndex: number, timeoutMs: number) => Promise; getActiveEditor: () => Editor; @@ -101,6 +102,7 @@ export async function goToAnchor({ pageGeometryHelper, painterHost, scrollContainer, + zoom, scrollPageIntoView, waitForPageMount, getActiveEditor, @@ -122,8 +124,10 @@ export async function goToAnchor({ // Find the page and fragment Y offset for the bookmark position. // selectionToRects often returns empty for bookmarks (zero-width inline nodes), // so we scan layout fragments to find the precise Y coordinate within the page. + // Note: rect?.y is document-absolute (not page-relative), so we only use pageIndex + // from the rect and always derive fragmentY from layout fragments. let pageIndex: number | null = rect?.pageIndex ?? null; - let fragmentY: number | null = rect?.top ?? null; + let fragmentY: number | null = null; if (pageIndex == null) { let nextFragmentPage: number | null = null; @@ -174,15 +178,19 @@ export async function goToAnchor({ const pageEl = getPageElementByIndex(painterHost, pageIndex); if (pageEl && fragmentY != null) { + // fragmentY is in layout-space (unscaled) pixels — scale to screen-space to match + // getBoundingClientRect() values which already account for CSS transform: scale(zoom). + const scaledY = fragmentY * zoom; + if (scrollContainer instanceof Element) { const pageRect = pageEl.getBoundingClientRect(); const containerRect = scrollContainer.getBoundingClientRect(); - const targetY = pageRect.top - containerRect.top + scrollContainer.scrollTop + fragmentY; + const targetY = pageRect.top - containerRect.top + scrollContainer.scrollTop + scaledY; scrollContainer.scrollTo({ top: targetY, behavior: 'instant' }); } else { // Window scroll const pageRect = pageEl.getBoundingClientRect(); - const targetY = pageRect.top + scrollContainer.scrollY + fragmentY; + const targetY = pageRect.top + scrollContainer.scrollY + scaledY; scrollContainer.scrollTo({ top: targetY, behavior: 'instant' }); } } else if (pageEl) { From 06f2d327e3bf54ec3717bd8f854b1dbeeac50377 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 17:33:38 -0300 Subject: [PATCH 11/13] test(toc): add behavior tests for TOC anchor click navigation Tests clicking TOC entry links and verifying: - Caret moves to the bookmark position (SD-2186) - Scroll position changes for cross-page navigation --- .../navigation/toc-anchor-scroll.spec.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/behavior/tests/navigation/toc-anchor-scroll.spec.ts diff --git a/tests/behavior/tests/navigation/toc-anchor-scroll.spec.ts b/tests/behavior/tests/navigation/toc-anchor-scroll.spec.ts new file mode 100644 index 0000000000..3c665326da --- /dev/null +++ b/tests/behavior/tests/navigation/toc-anchor-scroll.spec.ts @@ -0,0 +1,53 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { test, expect } from '../../fixtures/superdoc.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const DOC_PATH = path.resolve(__dirname, '../../test-data/layout/toc-with-heading2.docx'); + +test.skip(!fs.existsSync(DOC_PATH), 'Test document not available — run pnpm corpus:pull'); + +test('@behavior SD-2186: clicking TOC link scrolls to heading position', async ({ superdoc }) => { + await superdoc.loadDocument(DOC_PATH); + await superdoc.waitForStable(2000); + + // Record selection before click + const selBefore = await superdoc.getSelection(); + + // Find and click the first TOC entry link + const tocLink = superdoc.page.locator('.superdoc-toc-entry a.superdoc-link').first(); + await expect(tocLink).toBeVisible({ timeout: 10_000 }); + await tocLink.click(); + await superdoc.waitForStable(2000); + + // Verify the caret moved — goToAnchor calls setTextSelection at the bookmark position + const selAfter = await superdoc.getSelection(); + expect(selAfter.from).not.toBe(selBefore.from); +}); + +test('@behavior SD-2186: clicking different TOC links moves caret to different positions', async ({ superdoc }) => { + await superdoc.loadDocument(DOC_PATH); + await superdoc.waitForStable(2000); + + // Need at least 2 TOC entries to verify they navigate to different positions + const tocLinks = superdoc.page.locator('.superdoc-toc-entry a.superdoc-link'); + const count = await tocLinks.count(); + test.skip(count < 2, 'Document has fewer than 2 TOC entries'); + + // Click first TOC link and record caret position + const firstLink = tocLinks.first(); + await expect(firstLink).toBeVisible({ timeout: 10_000 }); + await firstLink.click(); + await superdoc.waitForStable(2000); + const selFirst = await superdoc.getSelection(); + + // Click last TOC link and verify caret moved to a different position + const lastLink = tocLinks.nth(count - 1); + await expect(lastLink).toBeVisible({ timeout: 10_000 }); + await lastLink.click(); + await superdoc.waitForStable(2000); + const selLast = await superdoc.getSelection(); + + expect(selLast.from).not.toBe(selFirst.from); +}); From 29703664c87ab00557e380af0e2207946b3873a1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 11 Mar 2026 20:57:16 +0000 Subject: [PATCH 12/13] chore(release): 1.18.2 [skip ci] ## [1.18.2](https://github.com/superdoc-dev/superdoc/compare/v1.18.1...v1.18.2) (2026-03-11) ### Bug Fixes * **anchor-nav:** use correct scroll container for sub-page bookmark navigation ([a300536](https://github.com/superdoc-dev/superdoc/commit/a300536111890565c6b53b0842551a5c2f4c191a)), closes [#scrollContainer](https://github.com/superdoc-dev/superdoc/issues/scrollContainer) * **rendering:** show comment highlight on text with Word highlight formatting ([f6d956e](https://github.com/superdoc-dev/superdoc/commit/f6d956ec38f12ff0ee3440f153edf1fa69406f2d)) * **toc:** correct zoom scaling and rect.top bug in anchor scroll ([16c768f](https://github.com/superdoc-dev/superdoc/commit/16c768f1b81672c5126833cc1ffbe948a2c11ebd)) --- packages/superdoc/CHANGELOG.md | 9 +++++++++ packages/superdoc/package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/superdoc/CHANGELOG.md b/packages/superdoc/CHANGELOG.md index 05ec055741..83d1526944 100644 --- a/packages/superdoc/CHANGELOG.md +++ b/packages/superdoc/CHANGELOG.md @@ -1,3 +1,12 @@ +## [1.18.2](https://github.com/superdoc-dev/superdoc/compare/v1.18.1...v1.18.2) (2026-03-11) + + +### Bug Fixes + +* **anchor-nav:** use correct scroll container for sub-page bookmark navigation ([a300536](https://github.com/superdoc-dev/superdoc/commit/a300536111890565c6b53b0842551a5c2f4c191a)), closes [#scrollContainer](https://github.com/superdoc-dev/superdoc/issues/scrollContainer) +* **rendering:** show comment highlight on text with Word highlight formatting ([f6d956e](https://github.com/superdoc-dev/superdoc/commit/f6d956ec38f12ff0ee3440f153edf1fa69406f2d)) +* **toc:** correct zoom scaling and rect.top bug in anchor scroll ([16c768f](https://github.com/superdoc-dev/superdoc/commit/16c768f1b81672c5126833cc1ffbe948a2c11ebd)) + ## [1.18.1](https://github.com/superdoc-dev/superdoc/compare/v1.18.0...v1.18.1) (2026-03-10) diff --git a/packages/superdoc/package.json b/packages/superdoc/package.json index a91dd447ab..818970443b 100644 --- a/packages/superdoc/package.json +++ b/packages/superdoc/package.json @@ -1,7 +1,7 @@ { "name": "superdoc", "type": "module", - "version": "1.18.1", + "version": "1.18.2", "license": "AGPL-3.0", "repository": { "type": "git", From cee3e9031875f95682cd37a71caf2042caa5df79 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Wed, 11 Mar 2026 18:30:06 -0300 Subject: [PATCH 13/13] ci: remove changelog generation from stable releases --- packages/superdoc/.releaserc.cjs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/superdoc/.releaserc.cjs b/packages/superdoc/.releaserc.cjs index ea1af9dd4b..aad6c86090 100644 --- a/packages/superdoc/.releaserc.cjs +++ b/packages/superdoc/.releaserc.cjs @@ -76,22 +76,12 @@ const isPrerelease = config.branches.some( ) if (!isPrerelease) { - // Add changelog BEFORE git - config.plugins.push([ - '@semantic-release/changelog', - { - changelogFile: 'CHANGELOG.md' - } - ]) - - // Git plugin comes AFTER npm and changelog + // Git plugin commits the version bump back to the branch. + // No changelog — release notes live on the GitHub release only. config.plugins.push([ '@semantic-release/git', { - assets: [ - 'CHANGELOG.md', - 'package.json' - ], + assets: ['package.json'], message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', },