0

I am attempting to pass a shared component to a <View fixed> element, however it appears that the output has missing style properties...

It appears that the child component's styling is preserved, but any grandchildren do not...

Further investigation shows that even hardcoding all of the <View>, <Text> and style also results in nested elements being stripped...

React-PDF Repl

enter image description here

Is there any reason why this is happening? Is there a way in which I can get the styles included?

const TableHeaders = () => (
    <TableRow>
        {['name', 'age', 'location'].map(label =>
            <TableCell>{label}</TableCell>)}
    </TableRow>
);

const TableRow = ({children}) => <View style={styles.row}>{children}</View>;

const TableCell = ({children}) => (
    <View style={styles.column}>
        <Text>{children}</Text>
    </View>
);

const FixedHeader = () => <View fixed render={() => <TableHeaders />} />;

const HardcodedHeader = () => (
  <View render={() => (
      <View style={styles.row}>
        {['name', 'age', 'location'].map(label => (
          <View style={styles.column}>
              <Text>{label}</Text>
          </View>
        ))}
      </View>
  )} />
)

const HardcodedHeaderWithHardcodedStyles = () => (
  <View render={() => (
      <View style={{
        flexDirection: 'row',
        backgroundColor: 'lightblue',
        borderRadius: 4,
        margin: '2px 0',
        padding: '10px 7px'
      }}>
        {['name', 'age', 'location'].map(label => (
          <View style={{
            margin: '0 5px',
            fontSize: 10,
            color: 'red'
          }}>
              <Text>{label}</Text>
          </View>
        ))}
      </View>
  )} />
)

const Quixote = () => (
  <Document>
    <Page style={styles.body}>
      <TableHeaders />
      <FixedHeader />
      <HardcodedHeader />
      <HardcodedHeaderWithHardcodedStyles />
    </Page>
  </Document>
);

const styles = StyleSheet.create({
  column: {
    margin: '0 5px',
    fontSize: 10,
    color: 'red'
  },
  row: {
    flexDirection: 'row',
    backgroundColor: 'lightblue',
    borderRadius: 4,
    margin: '2px 0',
    padding: '10px 7px'
  },
  body: {
    paddingTop: 35,
    paddingBottom: 65,
    paddingHorizontal: 35,
  }
});

ReactPDF.render(<Quixote />);

physicsboy
  • 5,656
  • 17
  • 70
  • 119

1 Answers1

0

SOLVED!

It turns out that yes, using the render={() => {}} prop to render elements with children does cause some headaches if you're not careful.

Margin and Padding

For Margin and Padding I was originally defining the values using a string format mirroring how we would do it within a proper css file:

{
   [margin|padding]: '[vertical]px [horizontal]px'
}

This must somehow get garbled by the render process and is misunderstood. After a lot of experimenting, it turns out that if we split out the definitions into their compoent parts and pass number values rather than strings, it's actually carried through properly (note: Numbers are interpreted as 'px' unless otherwise configged):

{
    marginTop: 2,
    marginBottom: 2,
    paddingTop: 10,
    paddingBottom: 10,
    paddingLeft: 7,
    paddingRight: 7
}

Fonts

Fonts are a little more strange. It seems that the render callback method somehow strips the association of fontFamily, fontSize, fontWeight etc from any child element from its parent. This means that we have to either redefine these parts in the <Text> element we want to style, or we can move the original definitions down to those <Text> elements from their <View> containers.

Persisting issues

The only thing that I couldn't get to work was the borderRadius.

See the new, updated Repl

physicsboy
  • 5,656
  • 17
  • 70
  • 119