Skip to content

Commit a743c90

Browse files
authored
add support for flex gap (#2160)
* setup flex gap * add types * throw error when gap is in percents * add changeset * fix tests
1 parent 17a8006 commit a743c90

10 files changed

Lines changed: 164 additions & 1 deletion

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@react-pdf/layout': minor
3+
'@react-pdf/renderer': minor
4+
'@react-pdf/stylesheet': minor
5+
'@react-pdf/types': minor
6+
---
7+
8+
implement flex gap

packages/layout/src/node/setGap.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Yoga from '@react-pdf/yoga';
2+
import { isNil, matchPercent } from '@react-pdf/fns';
3+
4+
const checkPercents = (attr, value) => {
5+
const percent = matchPercent(value);
6+
7+
if (percent) {
8+
throw new Error(`You can't pass percentage values to ${attr} property`);
9+
}
10+
};
11+
12+
/**
13+
* Set rowGap value to node's Yoga instance
14+
*
15+
* @param {Number} gap value
16+
* @param {Object} node instance
17+
* @return {Object} node instance
18+
*/
19+
export const setRowGap = value => node => {
20+
const { yogaNode } = node;
21+
22+
if (!isNil(value) && yogaNode) {
23+
checkPercents('rowGap', value);
24+
yogaNode.setGap(Yoga.GUTTER_ROW, value);
25+
}
26+
27+
return node;
28+
};
29+
30+
/**
31+
* Set columnGap value to node's Yoga instance
32+
*
33+
* @param {Number} gap value
34+
* @param {Object} node instance
35+
* @return {Object} node instance
36+
*/
37+
export const setColumnGap = value => node => {
38+
const { yogaNode } = node;
39+
40+
if (!isNil(value) && yogaNode) {
41+
checkPercents('columnGap', value);
42+
yogaNode.setGap(Yoga.GUTTER_COLUMN, value);
43+
}
44+
45+
return node;
46+
};

packages/layout/src/steps/resolveDimensions.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
setMinHeight,
5353
setMaxHeight,
5454
} from '../node/setDimension';
55+
import { setRowGap, setColumnGap } from '../node/setGap';
5556
import measureSvg from '../svg/measureSvg';
5657
import measureText from '../text/measureText';
5758
import measureImage from '../image/measureImage';
@@ -119,6 +120,8 @@ const setYogaValues = node => {
119120
setFlexBasis(node.style.flexBasis),
120121
setFlexGrow(node.style.flexGrow),
121122
setFlexShrink(node.style.flexShrink),
123+
setRowGap(node.style.rowGap),
124+
setColumnGap(node.style.columnGap),
122125
)(node);
123126
};
124127

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* eslint-disable react/no-array-index-key */
2+
import React from 'react';
3+
import { Document, Page, View } from '..';
4+
import renderToImage from './renderComponent';
5+
6+
const mount = async children => {
7+
const image = await renderToImage(
8+
<Document>
9+
<Page size={[100, 100]}>{children}</Page>
10+
</Document>,
11+
);
12+
13+
return image;
14+
};
15+
16+
const items = [
17+
'red',
18+
'red',
19+
'red',
20+
'green',
21+
'green',
22+
'green',
23+
'blue',
24+
'blue',
25+
'blue',
26+
];
27+
28+
describe('flex', () => {
29+
test('should support gap', async () => {
30+
const image = await mount(
31+
<View
32+
style={{
33+
height: '100%',
34+
width: '100%',
35+
display: 'flex',
36+
flexWrap: 'wrap',
37+
backgroundColor: '#e2e2e2',
38+
gap: 30,
39+
}}
40+
>
41+
{items.map((color, index) => (
42+
<View
43+
key={index}
44+
style={{
45+
width: 10,
46+
height: 10,
47+
backgroundColor: color,
48+
}}
49+
/>
50+
))}
51+
</View>,
52+
);
53+
54+
expect(image).toMatchImageSnapshot();
55+
});
56+
57+
test('should support rowGap and columnGap', async () => {
58+
const image = await mount(
59+
<View
60+
style={{
61+
height: '100%',
62+
width: '100%',
63+
display: 'flex',
64+
flexWrap: 'wrap',
65+
backgroundColor: '#e2e2e2',
66+
rowGap: '60px',
67+
columnGap: '80px',
68+
}}
69+
>
70+
{items.slice(0, 4).map((color, index) => (
71+
<View
72+
key={index}
73+
style={{
74+
width: 10,
75+
height: 10,
76+
backgroundColor: color,
77+
}}
78+
/>
79+
))}
80+
</View>,
81+
);
82+
83+
expect(image).toMatchImageSnapshot();
84+
});
85+
86+
test('should throw when value is percent', async () => {
87+
expect(mount(<View style={{ gap: '10%' }} />)).rejects.toThrow(
88+
"You can't pass percentage values to columnGap property",
89+
);
90+
});
91+
});

packages/renderer/tests/renderComponent.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const renderComponent = async element => {
8686
const source = await renderToBuffer(element);
8787

8888
const document = await pdfjs.getDocument({
89-
data: source.buffer,
89+
data: source,
9090
verbosity: 0,
9191
}).promise;
9292

381 Bytes
Loading
366 Bytes
Loading
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const expandGap = (key, value) => {
2+
const match = `${value}`.split(' ');
3+
4+
return {
5+
rowGap: match?.[0] || value,
6+
columnGap: match?.[1] || value,
7+
};
8+
};
9+
10+
export default expandGap;

packages/stylesheet/src/expand/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import {
1414
} from './paddings';
1515
import processObjectPosition from './objectPosition';
1616
import processTransformOrigin from './transformOrigin';
17+
import processGap from './gap';
1718

1819
const shorthands = {
1920
flex: processFlex,
21+
gap: processGap,
2022
margin: processMargin,
2123
marginHorizontal: processMarginHorizontal,
2224
marginVertical: processMarginVertical,

packages/types/style.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export interface Style {
1212
flexShrink?: number;
1313
flexBasis?: number | string;
1414
justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-around' | 'space-between' | 'space-evenly';
15+
gap?: number | string;
16+
rowGap?: number;
17+
columnGap?: number;
1518

1619
// Layout
1720

0 commit comments

Comments
 (0)