Skip to content

fix: preserve line spacing and indentation on Google Docs paste#2183

Merged
caio-pizzol merged 6 commits intosuperdoc-dev:mainfrom
gpardhivvarma:fix/preserve-line-spacing-indent-on-paste
Feb 27, 2026
Merged

fix: preserve line spacing and indentation on Google Docs paste#2183
caio-pizzol merged 6 commits intosuperdoc-dev:mainfrom
gpardhivvarma:fix/preserve-line-spacing-indent-on-paste

Conversation

@gpardhivvarma
Copy link
Contributor

@gpardhivvarma gpardhivvarma commented Feb 26, 2026

Summary

  • Add CSS inline style fallback in parseAttrs.js so line spacing (lineHeight), paragraph spacing (marginTop/marginBottom), indentation (marginLeft), and first-line/hanging indent (textIndent) are preserved when pasting from Google Docs or other sources that use inline CSS instead of SuperDoc's data-* attributes
  • Use a single parseCssLength helper backed by a CSS_LENGTH_TO_PT conversion map supporting pt, px, in, cm, mm — unrecognized units (em, rem, etc.) are safely ignored
  • Use exact 72 / 96 ratio for px→pt conversion, matching PX_PER_PT in pm-adapter
  • Correctly parse CSS line-height units: unitless and % values are stored as auto multipliers, while absolute lengths are stored as exact line spacing in twips
  • Line spacing formula inverts pm-adapter's normalizeLineValue (value * 1.15 / 240) so values round-trip correctly
  • Map positive text-indent to indent.firstLine and negative text-indent to indent.hanging
  • Preserve explicit zero margins (margin-top: 0) as 0 twips to prevent the style-engine from applying non-zero defaults
  • Fix pre-existing bug: skip Number() coercion for lineRule in data-spacing parsing to preserve the 'auto' string value
  • Data attributes still take priority, so existing DOCX paste behavior is unchanged

Closes #2151

Test plan

  • Paste from Google Docs with different line spacings (single, 1.5, double) and verify they are preserved
  • Paste indented paragraphs from Google Docs and verify indentation is preserved
  • Paste HTML with first-line and hanging indentation and verify correct rendering
  • Paste HTML with percentage/px/pt/in/cm/mm values and verify correct conversion
  • Paste HTML with explicit zero margins and verify no unintended spacing appears
  • Paste from Word and verify existing data-spacing/data-indent behavior is unchanged
  • Run pnpm test — all parseAttrs tests pass (28/28)

When pasting from Google Docs, line spacing and paragraph indentation
were lost because parseAttrs only read SuperDoc's internal data-*
attributes. Add CSS inline style fallback to extract lineHeight,
marginTop, marginBottom, and marginLeft from node.style and convert
to OOXML twips. Data attributes still take priority for regression safety.

Closes superdoc-dev#2151
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5937c7f1dc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@gpardhivvarma
Copy link
Contributor Author

@caio-pizzol

Handle %, px, and pt line-height values correctly instead of treating
all values as unitless multipliers. Percentage values are normalized
to a multiplier, while px/pt values are stored as exact line spacing.
@gpardhivvarma
Copy link
Contributor Author

gpardhivvarma commented Feb 26, 2026

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7aada6407e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Replace duplicated unit if/else chains with a single parseCssLength
helper backed by a CSS_LENGTH_TO_PT conversion map. Supports pt, px,
in, cm, mm; rejects unrecognized units (em, rem, etc.) to avoid
misinterpretation. Percentage lineHeight is normalized to a multiplier.
@gpardhivvarma
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57e66763b7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Allow zero-valued margins (margin-top: 0, etc.) through parseCssLength
so they are stored as 0 twips in paragraphProperties. This prevents the
style-engine from filling in non-zero defaults for paragraphs that
explicitly have no spacing/indent. Zero lineHeight remains rejected.
@gpardhivvarma
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aaf3c15a2c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@gpardhivvarma gpardhivvarma marked this pull request as draft February 26, 2026 08:49
Map text-indent to indent.firstLine (positive) or indent.hanging
(negative) so pasted HTML with first-line/hanging indentation renders
correctly. Allow negative values through parseCssLength for this case
while keeping >= 0 guards on margins and spacing callers.
@gpardhivvarma
Copy link
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Delightful!

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@gpardhivvarma gpardhivvarma marked this pull request as ready for review February 26, 2026 09:08
Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the contribution @gpardhivvarma!

the CSS fallback approach is solid and the test coverage is thorough.

left a few inline comments - nothing blocking, mostly small tweaks.

- Use exact 72/96 ratio for px→pt conversion (matches PX_PER_PT in pm-adapter)
- Add comment explaining the 1.15 inversion from normalizeLineValue
- Skip Number() coercion for lineRule to preserve 'auto' string value
- Update tests to use exact ratio and fix lineRule expectation
Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpardhivvarma all three items from last round are addressed — 72 / 96 is exact, lineRule is preserved, and the 1.15 comment makes the inversion clear. no new issues in the incremental diff.

tested locally — CSS spacing values (line-height, margin-top/bottom) are being picked up and converted to twips correctly on Google Docs paste. looks good to merge.

note: text-align (center/right/justify) is not preserved on paste either, should be fixed on another PR

@caio-pizzol caio-pizzol merged commit b9a7357 into superdoc-dev:main Feb 27, 2026
6 of 7 checks passed
@superdoc-bot
Copy link
Contributor

superdoc-bot bot commented Feb 27, 2026

🎉 This PR is included in superdoc v1.17.0-next.32

The release is available on GitHub release

@superdoc-bot
Copy link
Contributor

superdoc-bot bot commented Feb 27, 2026

🎉 This PR is included in superdoc-cli v0.2.0-next.27

The release is available on GitHub release

@gpardhivvarma
Copy link
Contributor Author

@gpardhivvarma all three items from last round are addressed — 72 / 96 is exact, lineRule is preserved, and the 1.15 comment makes the inversion clear. no new issues in the incremental diff.

tested locally — CSS spacing values (line-height, margin-top/bottom) are being picked up and converted to twips correctly on Google Docs paste. looks good to merge.

note: text-align (center/right/justify) is not preserved on paste either, should be fixed on another PR

Will look into it and create a new PR

gpardhivvarma added a commit to gpardhivvarma/superdoc that referenced this pull request Feb 27, 2026
Add CSS text-align fallback in parseAttrs to extract justification
from inline styles (e.g. `<p style="text-align: center">`), following
the same pattern as the existing spacing/indent CSS fallbacks from
PR superdoc-dev#2183. Maps CSS values (left, center, right, justify, start, end)
to OOXML justification values.
harbournick pushed a commit that referenced this pull request Feb 28, 2026
# [1.17.0](v1.16.0...v1.17.0) (2026-02-28)

### Bug Fixes

* active track change ([#2163](#2163)) ([108c14d](108c14d))
* add currentTotalPages getter and pagination-update event ([#2202](#2202)) ([95b4579](95b4579)), closes [#958](#958)
* always call resolveComment after custom TC bubble handlers (SD-2049) ([#2204](#2204)) ([34fb4e0](34fb4e0))
* backward replace insert text ([#2172](#2172)) ([66f0849](66f0849))
* **collaboration:** deduplicate updateYdocDocxData during replaceFile (SD-1920) ([#2162](#2162)) ([52962fc](52962fc))
* **comments:** cross-page collision avoidance for floating comment bubbles (SD-1998) ([#2180](#2180)) ([6cfbeca](6cfbeca))
* **comments:** remove synchronous dispatch from plugin apply() (SD-1940) ([#2157](#2157)) ([887175b](887175b))
* **css:** scope ProseMirror CSS to prevent bleeding into host apps (SD-1850) ([#2134](#2134)) ([b9d98fa](b9d98fa))
* document-api improvements, plan mode, query.match, mutations ([6221580](6221580))
* **document-api:** delete table cell fix ([#2209](#2209)) ([5e5c43f](5e5c43f))
* **document-api:** distribute columns command fixes ([#2207](#2207)) ([8f4eaf7](8f4eaf7))
* **document-api:** fix cell shading in document api ([#2215](#2215)) ([456f60e](456f60e))
* **document-api:** insert table cell ([#2210](#2210)) ([357ee90](357ee90))
* **document-api:** plan-engine reliability fixes and error diagnostics ([#2185](#2185)) ([abfd81b](abfd81b))
* **document-api:** split table cell command ([#2217](#2217)) ([0b3e2b4](0b3e2b4))
* **document-api:** split table command ([#2214](#2214)) ([ec31699](ec31699))
* **editor:** render styles applied inside SDT fields (SD-2011) ([#2188](#2188)) ([9c34be3](9c34be3))
* **editor:** selection highlight flickers when dragging across mark boundaries (SD-2024) ([#2205](#2205)) ([ba03e76](ba03e76))
* extract duplicate block identity normalization from docxImporter ([7f7ff93](7f7ff93))
* improve backspace behavior near run boundaries for tracked changes ([#2175](#2175)) ([6c9c7a3](6c9c7a3))
* **layout:** per-section footer constraints for multi-section docs (SD-1837) ([#2022](#2022)) ([e11acc5](e11acc5))
* normalize review namespace into trackChanges, harden input validation ([33e907b](33e907b))
* outside click for toolbar dropdown ([#2174](#2174)) ([5f859c7](5f859c7))
* preserve line spacing and indentation on Google Docs paste ([#2183](#2183)) ([b9a7357](b9a7357)), closes [#2151](#2151)
* **shapes:** render grouped DrawingML shapes with custom geometry (SD-1877) ❇️ ([#2105](#2105)) ([14985a5](14985a5))
* support cell spacing ([#1879](#1879)) ([1639967](1639967))
* **tables:** expand auto-width tables to fill available page width ([#2109](#2109)) ([15f36bc](15f36bc))
* text highlight on export ([#2189](#2189)) ([9cbd022](9cbd022))
* track highlight changes ([#2192](#2192)) ([e164625](e164625))
* undo/redo actions ([#2161](#2161)) ([495e92f](495e92f))

### Features

* allow custom accept/reject handlers for TC bubbles ([#1921](#1921)) ([e30abf6](e30abf6))
* **document-api:** add format operations font size alignment color font family ([#2179](#2179)) ([f19c688](f19c688))
* **document-api:** add plan-based mutation engine with query.match and style capture ([#2160](#2160)) ([365293a](365293a))
* **document-api:** doc default initial styles ([#2184](#2184)) ([f25e41f](f25e41f))
* **document-api:** include anchored text in comments list response ([#2177](#2177)) ([b3a2912](b3a2912))
* **document-api:** inline formatting parity core end-to-end ([#2197](#2197)) ([b405b03](b405b03))
* **document-api:** inline formatting rpr parity ([#2198](#2198)) ([41ab771](41ab771))
* **document-api:** section commands ([#2199](#2199)) ([ec4abe3](ec4abe3))
* **document-api:** support deleting entire block nodes not only text ([#2181](#2181)) ([2897246](2897246))
* **document-api:** table of contents commands ([#2200](#2200)) ([baa72c4](baa72c4))
* **document-api:** tables namespace and commands ([#2182](#2182)) ([b80ee31](b80ee31))
* **markdown:** add markdown override to sdk, improve conversion ([#2196](#2196)) ([04a1c71](04a1c71))
* preserve w:view setting through DOCX round-trip ([#2190](#2190)) ([48b4210](48b4210)), closes [#2070](#2070)
* **track-changes:** clear comment bubbles when bulk accept or reject TCs ([#2159](#2159)) ([27fbe8e](27fbe8e))

### Performance Improvements

* **comments:** batch tracked change comment creation on load ([#2166](#2166)) ([0c2eca5](0c2eca5))
* **comments:** batch tracked change creation and virtualize floating bubbles (SD-1997) ([#2168](#2168)) ([70fd7d9](70fd7d9))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preserve line spacing and indentation on Google Docs paste

2 participants