diegomura / react-pdf

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

fontFamily is not loaded / applied if it is only used in render callbacks #2850

Open crowbait opened 3 weeks ago

crowbait commented 3 weeks ago

I'm registering two fonts, one is a logo type and the other is the font I want to use for the document body.

However, while the logo type works well, I think the other one is not (it's a bit difficult to tell because it doesn't look very different from the default one). Also, setting the fontWeight doesn't work at all - I have already tried the previously suggested solutions of specifiying the fontFamily alongside the fontWeight in inline styles and downgrading to "@react-pdf/layout": "3.11.5", "@react-pdf/renderer": "3.4.2",.

ReactPDF.Font.register({family: 'Logotype', src: Logotype});
ReactPDF.Font.register({family: 'Lato', fonts: [
    {src: Lato},
    {src: LatoBold, fontWeight: 'bold'},
    {src: LatoBoldItalic, fontWeight: 'bold', fontStyle: 'italic'},
    {src: LatoItalic, fontStyle: 'italic'},
    {src: LatoLight, fontWeight: 'light'},
    {src: LatoLightItalic, fontWeight: 'light', fontStyle: 'italic'},
  ]});
<Document>
      <Page size="A4" style={{
        fontFamily: 'Lato',
        padding: pageMargins,
        fontSize: '11pt'
      }}>
        <View id="header" style={{
          display: 'flex',
          flexDirection: 'row',
          justifyContent: 'space-between',
          alignItems: 'flex-start'
        }}>
          <View id="header-content" render={({pageNumber}) => {
            if (pageNumber === 1) return (
              <View id="header-primary" style={{display: 'flex', flexDirection: 'column', alignItems: 'flex-end'}}>
                <Text style={{fontSize: '16pt', fontFamily: 'Lato', fontWeight: 'bold'}}>TITLE</Text>
                <Text>subTitle</Text>
                <Text style={{fontFamily: 'Lato', fontWeight: 'bold'}}>NAME</Text>
              </View>
            )
          }} />
        </View>

        {...}
      </Page>
    </Document>

I've also tried using another FontFamily for bold text with no success:

ReactPDF.Font.register({family: 'Lato-Bold', src: LatoBold});
<Text style={{fontSize: '16pt', fontFamily: 'Lato-Bold'}}>TITLE</Text>
crowbait commented 3 weeks ago

After too much experimentation I could determine that fontFamily is not applied (or the font not actually loaded) if the font is only used in a conditional render callback.

Example:

<View id="header-content" render={({pageNumber}) => {
    if (pageNumber === 1) return (
        <Text style={{fontFamily: 'only-used-here'}}>Special</Text>
    );
    return (
        <Text>Standard font used in the rest of the document (can be registered from ttf just fine)</Text>
    );
</View>
<Text>Other Content</Text>

In the example above, "Special" will fall back to the global default font. Not the one specified in a higher View or the Page, but (in my case) Helvetica.

Now, if we add an element to the tree which is rendered the normal way (without render callback), it works:

<View id="header-content" render={({pageNumber}) => {
    if (pageNumber === 1) return (
        <Text style={{fontFamily: 'not-only-used-here'}}>Special</Text>
    );
    return (
        <Text>Standard font used in the rest of the document (can be registered from ttf just fine)</Text>
    );
</View>
<Text>Other Content</Text>
<Text style={{fontFamily: 'not-only-used-here'}}>Special</Text>

As a workaround, it should be noted that the element doesn't have to be visible:

...
<Text>Other Content</Text>
<Text style={{fontFamily: 'not-only-used-here', color: '#ffffff'}}>Special</Text>