Skip to content

Commit

Permalink
feat: support multiple line-height units (#2952)
Browse files Browse the repository at this point in the history
  • Loading branch information
diegomura authored Nov 17, 2024
1 parent 9075655 commit 2c3c887
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 8 deletions.
6 changes: 6 additions & 0 deletions .changeset/tame-yaks-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@react-pdf/layout": patch
"@react-pdf/stylesheet": patch
---

feat: support multiple line-height units
2 changes: 1 addition & 1 deletion packages/layout/src/text/getAttributedString.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const getFragments = (fontStore, instance, parentLink, level = 0) => {
color,
opacity,
fontSize,
lineHeight,
direction,
verticalAlign,
backgroundColor,
Expand All @@ -81,7 +82,6 @@ const getFragments = (fontStore, instance, parentLink, level = 0) => {
strikeColor: textDecorationColor || color,
underlineColor: textDecorationColor || color,
link: parentLink || instance.props?.src || instance.props?.href,
lineHeight: lineHeight ? lineHeight * fontSize : null,
align: textAlign || (direction === 'rtl' ? 'right' : 'left'),
};

Expand Down
16 changes: 9 additions & 7 deletions packages/stylesheet/src/transform/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ import transformUnits from './units';
import transformColor from './colors';
import processTransform from './transform';
import processFontWeight from './fontWeight';
import processLineHeight from './lineHeight';
import processObjectPosition from './objectPosition';
import processTransformOrigin from './transformOrigin';
import castFloat from '../utils/castFloat';

const handlers = {
transform: processTransform,
fontWeight: processFontWeight,
lineHeight: processLineHeight,
objectPositionX: processObjectPosition,
objectPositionY: processObjectPosition,
transformOriginX: processTransformOrigin,
transformOriginY: processTransformOrigin,
};

const transformStyle = (key, value, container) => {
const result = handlers[key] ? handlers[key](value) : value;
const transformStyle = (key, value, styles, container) => {
const result = handlers[key] ? handlers[key](value, styles) : value;

return transformColor(transformUnits(container, castFloat(result)));
};
Expand All @@ -33,16 +35,16 @@ const transformStyle = (key, value, container) => {
* @param {Object} container
* @returns {Transform} transform function
*/
const transform = (container) => (style) => {
if (!style) return style;
const transform = (container) => (styles) => {
if (!styles) return styles;

const propsArray = Object.keys(style);
const propsArray = Object.keys(styles);
const resolvedStyle = {};

for (let i = 0; i < propsArray.length; i += 1) {
const key = propsArray[i];
const value = style[key];
const transformed = transformStyle(key, value, container);
const value = styles[key];
const transformed = transformStyle(key, value, styles, container);

resolvedStyle[key] = transformed;
}
Expand Down
18 changes: 18 additions & 0 deletions packages/stylesheet/src/transform/lineHeight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* eslint-disable no-restricted-globals */

import { matchPercent } from '@react-pdf/fns';

const processLineHeight = (value, styles) => {
if (value === '') return value;

const { fontSize = 18 } = styles;

// Percent values: use this number multiplied by the element's font size
const { percent } = matchPercent(value) || {};
if (percent) return percent * fontSize;

// Unitless values: use this number multiplied by the element's font size
return isNaN(value) ? value : value * fontSize;
};

export default processLineHeight;
50 changes: 50 additions & 0 deletions packages/stylesheet/tests/transform.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,56 @@ describe('stylesheet transform', () => {
});
});

describe('transform lineHeight', () => {
test('should transform unitless number amount', () => {
const styles = transformStyles({ lineHeight: 2 });

expect(styles.lineHeight).toBe(18 * 2);
});

test('should transform unitless number amount with font-size', () => {
const styles = transformStyles({ lineHeight: 2, fontSize: 10 });

expect(styles.lineHeight).toBe(10 * 2);
});

test('should transform unitless string amount', () => {
const styles = transformStyles({ lineHeight: '2' });

expect(styles.lineHeight).toBe(18 * 2);
});

test('should transform unitless string amount with font-size', () => {
const styles = transformStyles({ lineHeight: '2', fontSize: 10 });

expect(styles.lineHeight).toBe(10 * 2);
});

test('should transform percentage amount', () => {
const styles = transformStyles({ lineHeight: '200%' });

expect(styles.lineHeight).toBe(18 * 2);
});

test('should transform percentage amount with font-size', () => {
const styles = transformStyles({ lineHeight: '200%', fontSize: 10 });

expect(styles.lineHeight).toBe(10 * 2);
});

test('should transform height px dimensions', () => {
const styles = transformStyles({ lineHeight: '20px' });

expect(styles.lineHeight).toBe(20);
});

test('should transform width mm dimensions', () => {
const styles = transformStyles({ lineHeight: '20mm' });

expect(styles.lineHeight).toBeCloseTo(56.69, 1);
});
});

describe('transform colors', () => {
test('should keep hex values as they are', () => {
const styles = transformStyles({ color: '#0000FF' });
Expand Down

0 comments on commit 2c3c887

Please sign in to comment.