diegomura / diegomura/react-pdf
Text layout can be wider than node's width
- Dominant language
- TypeScript
- Stars
- 16.8k
- Forks
- 1.3k
- Avg merge
- 5h 6m
- Merged PRs (30d)
- 52
Description
**Describe the bug**
In certain contexts, a text node's layout is calculated using a larger width than the node itself, resulting in text overflowing outside its intended container.
**To Reproduce**
[react-pdf REPL](https://react-pdf.org/repl?code=3187b0760ce02e0040b204f00889805702d814ccb02f0c005009431e01f110140c3003c2badaee4db7d00280860399633404006cb1e00de62600072e004d6404b303c0170c00ec00986005f1d316560046687ab76ece8035055803b80a8c34449800cc4400f240a01396602805703500725f103b50dd7d431333360b5a6b5b07411171493b055928000b3500660036001a183cac051e3ca822e29883635318007a7324e480152c4f5838d30eceda0019107f0c180529084c031021718105582e6c2872d04800a82c28345f183969850860251e182c2115f2882c5979ab8534080c1047dd8c2925a573c5591a17030342c0845c2338df87b79a2dfc300c2f0c05c238dc008e682e000e8600055580e0149339022944498000dd096b728634e3030081a0be3423d7a585f39ca05c20b804142704614030706437cf4b029c1420d5ba2d0d32ba78ae28d0061deb2100c0b6f70c4f27148794408ea0fe1f80efc0d5c2a660183f8a4fe4a9810ce2d8129290b34149b9bb4a75c5657083dcb50a015cd2d50ab9a1dca6050f21968014a264e29e41c7100514f300b05eac01d96c0d4300b80138fa0a4391e5c71936fb48072380d80881ae9b7a08432181d26020371b814e714619ee2ce07bc05feae24b263900d8221e34c16312493a2b47a7d21a595a367b16ed7dc3e074d78c4c23758c40037150a800252c171021c24000c4b1fe2747308744429f98b0768af2a0800000)
```tsx
const MyDocument = () => (
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
);
ReactPDF.render();
```
This REPL shows a flex row containing a fixed width item (in this case a `View`) followed by a `Text` element containing long wrapped text. Though `debug` shows that the node widths are correctly sized (flex row width of 451, fixed size child width of 33 and text child width of 418), the text lines are broken such that the content visually overflows outside the parent container.
**Expected behavior**
The text content should be no larger than 418 units wide and be visually constricted to its container (that is, not overflowing into the green padding)
**Screenshots**

**Investigation**
(take everything here with a grain of salt - first time digging into this repo or anything Yoga-related)
Upon initially debugging, I found that the text node's `lines` are being generated in a way that causes this overflow - for example, the first line ending in the word "elit" rather than ending on something more appropriate like "adipiscing". This eventually led me to `layoutText`:
https://github.com/diegomura/react-pdf/blob/089e2d4f4bb7f918c71895960d2639887c1ae6d9/packages/layout/src/text/layoutText.js#L64-L80
Interestingly, this is is being called with a `width` of `451.280029296875` rather than the expected size of `418` (matching what `debug` reports as the node's size). This likely explains the `lines` behavior - textkit is splitting the text assuming is has more width than is actually should.
Looking upstream, `layoutText` is being called by `measureText` which is also invoked with the larger-than-expected width. `measureText` seems to be called by Yoga directly via `setMeasureFunc`:
https://github.com/diegomura/react-pdf/blob/089e2d4f4bb7f918c71895960d2639887c1ae6d9/packages/layout/src/steps/resolveDimensions.js#L140-L145
At this point, I'm a bit lost as to why Yoga would invoke this with the larger `width` value. Perhaps somewhere in Yoga node creation there needs to be a different width value set?
I also discovered that inspecting the text's `yogaNode.getComputedWidth()` at a later stage (for example, [after `calculateLayout` has been called for the root `page`](https://github.com/diegomura/react-pdf/blob/089e2d4f4bb7f918c71895960d2639887c1ae6d9/packages/layout/src/steps/resolveDimensions.js#L199)) returns the expected value of ~`418` - not sure why this value is different than the one provided by Yoga in the measure stage.
**Desktop (please complete the following information):**
- OS: macOS 13.2
- Browser: Chrome 109, though I can also reproduce in Node v18.8.0 via `renderToFile`
- React-pdf version: v3.1.3 (REPL seems to use v3.0.0), though I've also reproduced using a local build of the latest `master` (`089e2d4`)
Contributor guide
Assessment
This issue has not been assessed yet.