Skip to content

Commit

Permalink
add support for flex gap (#2160)
Browse files Browse the repository at this point in the history
* setup flex gap

* add types

* throw error when gap is in percents

* add changeset

* fix tests
  • Loading branch information
jeetiss authored Jan 28, 2023
1 parent 17a8006 commit a743c90
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .changeset/healthy-lobsters-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@react-pdf/layout': minor
'@react-pdf/renderer': minor
'@react-pdf/stylesheet': minor
'@react-pdf/types': minor
---

implement flex gap
46 changes: 46 additions & 0 deletions packages/layout/src/node/setGap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Yoga from '@react-pdf/yoga';
import { isNil, matchPercent } from '@react-pdf/fns';

const checkPercents = (attr, value) => {
const percent = matchPercent(value);

if (percent) {
throw new Error(`You can't pass percentage values to ${attr} property`);
}
};

/**
* Set rowGap value to node's Yoga instance
*
* @param {Number} gap value
* @param {Object} node instance
* @return {Object} node instance
*/
export const setRowGap = value => node => {
const { yogaNode } = node;

if (!isNil(value) && yogaNode) {
checkPercents('rowGap', value);
yogaNode.setGap(Yoga.GUTTER_ROW, value);
}

return node;
};

/**
* Set columnGap value to node's Yoga instance
*
* @param {Number} gap value
* @param {Object} node instance
* @return {Object} node instance
*/
export const setColumnGap = value => node => {
const { yogaNode } = node;

if (!isNil(value) && yogaNode) {
checkPercents('columnGap', value);
yogaNode.setGap(Yoga.GUTTER_COLUMN, value);
}

return node;
};
3 changes: 3 additions & 0 deletions packages/layout/src/steps/resolveDimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
setMinHeight,
setMaxHeight,
} from '../node/setDimension';
import { setRowGap, setColumnGap } from '../node/setGap';
import measureSvg from '../svg/measureSvg';
import measureText from '../text/measureText';
import measureImage from '../image/measureImage';
Expand Down Expand Up @@ -119,6 +120,8 @@ const setYogaValues = node => {
setFlexBasis(node.style.flexBasis),
setFlexGrow(node.style.flexGrow),
setFlexShrink(node.style.flexShrink),
setRowGap(node.style.rowGap),
setColumnGap(node.style.columnGap),
)(node);
};

Expand Down
91 changes: 91 additions & 0 deletions packages/renderer/tests/gap.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import { Document, Page, View } from '..';
import renderToImage from './renderComponent';

const mount = async children => {
const image = await renderToImage(
<Document>
<Page size={[100, 100]}>{children}</Page>
</Document>,
);

return image;
};

const items = [
'red',
'red',
'red',
'green',
'green',
'green',
'blue',
'blue',
'blue',
];

describe('flex', () => {
test('should support gap', async () => {
const image = await mount(
<View
style={{
height: '100%',
width: '100%',
display: 'flex',
flexWrap: 'wrap',
backgroundColor: '#e2e2e2',
gap: 30,
}}
>
{items.map((color, index) => (
<View
key={index}
style={{
width: 10,
height: 10,
backgroundColor: color,
}}
/>
))}
</View>,
);

expect(image).toMatchImageSnapshot();
});

test('should support rowGap and columnGap', async () => {
const image = await mount(
<View
style={{
height: '100%',
width: '100%',
display: 'flex',
flexWrap: 'wrap',
backgroundColor: '#e2e2e2',
rowGap: '60px',
columnGap: '80px',
}}
>
{items.slice(0, 4).map((color, index) => (
<View
key={index}
style={{
width: 10,
height: 10,
backgroundColor: color,
}}
/>
))}
</View>,
);

expect(image).toMatchImageSnapshot();
});

test('should throw when value is percent', async () => {
expect(mount(<View style={{ gap: '10%' }} />)).rejects.toThrow(
"You can't pass percentage values to columnGap property",
);
});
});
2 changes: 1 addition & 1 deletion packages/renderer/tests/renderComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const renderComponent = async element => {
const source = await renderToBuffer(element);

const document = await pdfjs.getDocument({
data: source.buffer,
data: source,
verbosity: 0,
}).promise;

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions packages/stylesheet/src/expand/gap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const expandGap = (key, value) => {
const match = `${value}`.split(' ');

return {
rowGap: match?.[0] || value,
columnGap: match?.[1] || value,
};
};

export default expandGap;
2 changes: 2 additions & 0 deletions packages/stylesheet/src/expand/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import {
} from './paddings';
import processObjectPosition from './objectPosition';
import processTransformOrigin from './transformOrigin';
import processGap from './gap';

const shorthands = {
flex: processFlex,
gap: processGap,
margin: processMargin,
marginHorizontal: processMarginHorizontal,
marginVertical: processMarginVertical,
Expand Down
3 changes: 3 additions & 0 deletions packages/types/style.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export interface Style {
flexShrink?: number;
flexBasis?: number | string;
justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-around' | 'space-between' | 'space-evenly';
gap?: number | string;
rowGap?: number;
columnGap?: number;

// Layout

Expand Down

0 comments on commit a743c90

Please sign in to comment.