diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.94k stars 1.18k forks source link

Add Ellipsis to Text #461

Closed arahansen closed 5 years ago

arahansen commented 5 years ago

Is your feature request related to a problem? Please describe. I'm looking to add ellipses to my text rendering. It looks like pdfkit handles this, but react-pdf uses a custom layout engine that (from what I can tell) does not call out to pdfkit.

Is this a feature that react-pdf could support? I started digging in a little, but couldn't really find where to get started.

Describe the solution you'd like An API that would be nice for this use case would be to handle it in the stylesheet ie:

const styles = StyleSheet.create({
  myText: {
    textWrap: 'nowrap',
    textOverflow: 'ellipsis'
  }
})

Describe alternatives you've considered I suppose this could also be done as a prop on the Text component as well, but this seems a styling concern.

Alternatively, would it be possible to use pdfkit for an alternative Text layout? (for example, SimpleText or something along those lines). I'm assuming react-pdf is not using pdfkit because the layout there is not powerful enough, or not compatible with yoga.

Additional context

arahansen commented 5 years ago

Here is a (pretty hacky) prototype of something that I may be able to leverage to get what I'm looking for. Using a theoretical maxLines prop on Text.

Basically, since textkit is already doing the heavy lifting to truncate the string, I would be able to use the first line found to determine the cutoff point. I still would need to be able to customize the hyphenization token, which would be a change in textkit afaict.

diegomura commented 5 years ago

Thanks @arahansen ! I agree this is a cool feature to have, but unfortunately react-pdf does not support it yet.

It's true we don't rely on pdfkit text and line breaking logic. We use textkit to perform these tasks, which was coded to produce much more higher quality text, plus Knuth & Plass line breaking algorithm and many other cool features. Imo this is something that should be implemented in textkit itself, since involves mutating the glyphs when text ran out of space.

Hope I can tackle this soon, but if you would like to give it a shot I'll be happy to help on the onboarding!

arahansen commented 5 years ago

yeah, I'd love to take a look into this. So far looking at textkit, I see we have access to the glyphs and could potentially override them.

The approach I'm seeing here seems pretty use-case specific which doesn't seem great:

ie, we have:

// pseudo-code model
{ lines: ['abc-', 'def'] }

we could maybe assume if:

lines.length > maxLines

then:

// pseudo-code

const lines = [lines[0]] // remove excess lines
let glyphs = line.glyphRuns[0].glyphs
glyphs = glyphs.slice(0, glyphs.length - 1) // remove last glyph (assuming its a hyphen)

This doesn't seem right since the fact that the first line has a hyphen that connects to the next line seems like an implementation detail of react-pdf.

any additional on-boarding help you might be able to provide would be very much appreciated!

arahansen commented 5 years ago

Digging into this a bit more, I'm not quite sure the best way to go about this. Seems like Yoga does not provide a reliable container height (it usually returns NaN here) so I'm not seeing how we can determine the height at which to truncate text, since it ends up being the page height.

Any ideas on how to tackle this?

arahansen commented 5 years ago

This also seems to be the cause (at least partially?) for overflowing text like this which I can't seem to find a solution for:

image

tommmyy commented 5 years ago

This is still not working... In example bellow: 1) instead of ... there is & 2) since there is no word-wrap or word-break, the text is overflowing.

https://react-pdf.org/repl?code=140630f60760ce02e004015021808c03605338178eb027a6009807401a8096180ee001911540039a4be0171c32a980dc7350a446000b764802b8c30fc518004e4433c80ca310864e50c1a21b2152f901d4868ce0119f62e500942807311304f0b17000315c30084c0c6900b62e661eb4bcc0a090b088363878eac4e45474c0006698001e002214f218203014909cf260d4fc0148f2f61410e252606111e0d0f008597104899434b4c082ae9c004c00ac00a45eca6a1a5a3a7a7072d6c6a66e960b06ca003218a9ce2b9c9eeb4b08604cc16e9e00e4c04d91ad88089d0918a4081819307d95d5b59c92d2152a8d420272627046fc54a40602a0a000bcb0e64f0ddc2cd28bc06c1826029e0b800050012870003e381e380703800078b260100480218080c18914ca752000a487b06159ecf655390e85e5c0d9fcca60a6ca4b178a25ed696cb65828431239a5220480a54803d0205532a56eab20ac55cb8da2d37f395c4843e098181d5ea4da6c779a0de2c15bb2d02a747394452223a5516cb6bb9d8acf7865dbef9050400edd707dd56a354605baa948695084cf267d5eef7529d98a401400b41cac800c4836994fcab31186de6ad4e80331c000aa50653531375f4f37bd91c6f46554377398009c65f710ccb13b8196e01389ecfe7d3dae8e3da996d160bc3a748d0035045bbdd87b7128cda71d3c5e4ca755c9e5f2fbb4fa63399ac826a3802582a56ab120f20810c3c4a94c5b1791e06d5896fd802000

si-le-mao commented 3 years ago

I have a trick for this by using height property

<View style={{ display: 'flex', flexDirection: 'row', height: 10 }}>
    <View style={{ flex: 1 }}>
        <Text>NNNNNNNNNN NNNNNNNNNN NNNNNNNNNN NNNNNNNNNN NNNNNNNNNN</Text>
    </View>
</View>