Skip to content

Commit

Permalink
feat: add font feature settings support
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanwittwer committed May 5, 2024
1 parent ee126d6 commit f33ad19
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .changeset/six-paws-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@react-pdf/textkit": minor
"@react-pdf/layout": minor
"@react-pdf/types": minor
---

Add support for fontFeatureSettings to customise ligatures, tabular number display, and other font features
81 changes: 81 additions & 0 deletions packages/examples/src/fontFeatureSettings/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* eslint react/prop-types: 0 */
/* eslint react/jsx-sort-props: 0 */

import { Document, Font, Page, StyleSheet, Text } from '@react-pdf/renderer';
import React from 'react';

import RobotoFont from '../../public/Roboto-Regular.ttf';
import RubikFont from '../../public/Rubik-Regular.ttf';

const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 45,
paddingHorizontal: 35,
position: 'relative',
fontSize: 14,
},
headline: {
fontFamily: 'Roboto',
fontSize: '24',
paddingVertical: 12,
},
rubik: {
fontFamily: 'Rubik',
},
roboto: {
fontFamily: 'Roboto',
},
tabular: {
fontFeatureSettings: ['tnum'],
},
smallCapitals: {
fontFeatureSettings: ['smcp'],
},
disableCommonLigatures: {
fontFeatureSettings: { liga: 0 },
},
});

Font.register({
family: 'Rubik',
fonts: [{ src: RubikFont, fontWeight: 400 }],
});
Font.register({
family: 'Roboto',
fonts: [{ src: RobotoFont, fontWeight: 400 }],
});

const MyDoc = () => {
const longNumberExample = "012'345'678'901";
const commonLigaturesExample = 'A firefighter from Sheffield';
return (
<Page style={styles.body}>
<Text style={styles.headline}>Rubik</Text>
<Text style={styles.rubik}>{longNumberExample} – Default features</Text>
<Text style={[styles.rubik, styles.tabular]}>
{longNumberExample} – Tabular numbers
</Text>
<Text style={styles.headline}>Roboto</Text>
<Text style={styles.roboto}>
{commonLigaturesExample} – Default features
</Text>
<Text style={[styles.roboto, styles.disableCommonLigatures]}>
{commonLigaturesExample} – Common ligatures off
</Text>
<Text style={[styles.roboto, styles.smallCapitals]}>
{commonLigaturesExample} – Small capitals
</Text>
</Page>
);
};

const App = () => {
return (
<Document>
<MyDoc />
</Document>
);
};

export default App;
1 change: 1 addition & 0 deletions packages/layout/src/steps/resolveInheritance.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const BASE_INHERITABLE_PROPERTIES = [
'fontSize',
'fontStyle',
'fontWeight',
'fontFeatureSettings',
'letterSpacing',
'opacity',
'textDecoration',
Expand Down
1 change: 1 addition & 0 deletions packages/layout/src/svg/inheritProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const SVG_INHERITED_PROPS = [
'fontSize',
'fontStyle',
'fontWeight',
'fontFeatureSettings',
'letterSpacing',
'opacity',
'textDecoration',
Expand Down
2 changes: 2 additions & 0 deletions packages/layout/src/text/getAttributedString.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const getFragments = (fontStore, instance, parentLink, level = 0) => {
fontWeight,
fontStyle,
fontSize = 18,
fontFeatureSettings,
textAlign,
lineHeight,
textDecoration,
Expand Down Expand Up @@ -83,6 +84,7 @@ const getFragments = (fontStore, instance, parentLink, level = 0) => {
link: parentLink || instance.props?.src || instance.props?.href,
lineHeight: lineHeight ? lineHeight * fontSize : null,
align: textAlign || (direction === 'rtl' ? 'right' : 'left'),
features: fontFeatureSettings,
};

for (let i = 0; i < instance.children.length; i += 1) {
Expand Down
4 changes: 4 additions & 0 deletions packages/layout/tests/steps/resolveInhritance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,8 @@ describe('layout resolveInheritance', () => {
test('Should inherit textAlign value', shouldInherit('textAlign'));
test('Should inherit visibility value', shouldInherit('visibility'));
test('Should inherit wordSpacing value', shouldInherit('wordSpacing'));
test(
'Should inherit fontFeatureSettings value',
shouldInherit('fontFeatureSettings'),
);
});
4 changes: 2 additions & 2 deletions packages/textkit/src/layout/generateGlyphs.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const layoutRun = (string) => {
*/
return (run) => {
const { start, end, attributes = {} } = run;
const { font } = attributes;
const { font, features } = attributes;

if (!font) return { ...run, glyphs: [], glyphIndices: [], positions: [] };

Expand All @@ -60,7 +60,7 @@ const layoutRun = (string) => {
// passing LTR To force fontkit to not reverse the string
const glyphRun = font.layout(
runString,
undefined,
features,
undefined,
undefined,
'ltr',
Expand Down
1 change: 1 addition & 0 deletions packages/types/style.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export interface Style {
| 'extrabold'
| 'heavy'
| 'black';
fontFeatureSettings?: string[] | Record<string, boolean>;
letterSpacing?: number | string;
lineHeight?: number | string;
maxLines?: number; // ?
Expand Down

0 comments on commit f33ad19

Please sign in to comment.