feat(pdf): roll out shared RTL layout to all templates

Introduce createRtlStyleHelpers and a single rtl flag on RenderProvider,
migrate every template page to mirrored layout styles, and rename
alignRight to alignEnd. Fix plain rich text rendering via PdfText
paragraph renderers and map legacy Times New Roman to Times-Roman.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Amruth Pillai
2026-05-25 16:29:50 +02:00
co-authored by Cursor
parent 86fff7237f
commit 24c882fa9f
28 changed files with 501 additions and 276 deletions
@@ -12,6 +12,7 @@ import { getTemplateMetrics } from "../shared/metrics";
import { getTemplatePageMinHeightStyle, getTemplatePageSize } from "../shared/page-size";
import { hasTemplatePicture } from "../shared/picture";
import { Heading, Icon, Link, Text } from "../shared/primitives";
import { createRtlStyleHelpers } from "../shared/rtl";
import { Section } from "../shared/sections";
import { composeStyles, headerNameLineHeight } from "../shared/styles";
@@ -111,9 +112,10 @@ const Header = ({ styles }: { styles: KakunaStyles }) => {
};
const useKakunaTemplate = (): KakunaTemplate => {
const { picture, metadata } = useRender();
const { picture, metadata, rtl } = useRender();
return useMemo(() => {
const r = createRtlStyleHelpers(rtl);
const foreground = rgbaStringToHex(metadata.design.colors.text);
const background = rgbaStringToHex(metadata.design.colors.background);
const primary = rgbaStringToHex(metadata.design.colors.primary);
@@ -126,6 +128,7 @@ const useKakunaTemplate = (): KakunaTemplate => {
fontWeight: metadata.typography.body.fontWeights[0] ?? "400",
lineHeight: metadata.typography.body.lineHeight,
color: foreground,
...r.text,
} satisfies Style;
const baseStyles = StyleSheet.create({
@@ -138,6 +141,7 @@ const useKakunaTemplate = (): KakunaTemplate => {
fontFamily: metadata.typography.body.fontFamily,
fontSize: metadata.typography.body.fontSize,
lineHeight: metadata.typography.body.lineHeight,
direction: r.pageDirection,
},
text: bodyText,
heading: {
@@ -146,13 +150,14 @@ const useKakunaTemplate = (): KakunaTemplate => {
fontWeight: metadata.typography.heading.fontWeights.at(-1) ?? "600",
lineHeight: metadata.typography.heading.lineHeight,
color: foreground,
...r.text,
},
div: {
rowGap: metrics.gapY(0.125),
columnGap: metrics.gapX(1 / 3),
},
inline: {
flexDirection: "row",
flexDirection: r.row,
alignItems: "center",
columnGap: metrics.gapX(1 / 3),
},
@@ -176,26 +181,23 @@ const useKakunaTemplate = (): KakunaTemplate => {
alignItems: "flex-start",
},
richListItemMarker: {
width: metadata.typography.body.fontSize,
textAlign: "right",
...bodyText,
width: metadata.typography.body.fontSize,
textAlign: r.listMarkerTextAlign,
},
richListItemContent: {
flex: 1,
...bodyText,
},
splitRow: {
flexDirection: "row",
flexDirection: r.row,
flexWrap: "wrap",
alignItems: "flex-start",
justifyContent: "space-between",
columnGap: metrics.gapX(2 / 3),
},
alignRight: {
textAlign: "right",
minWidth: 0,
maxWidth: "100%",
flexShrink: 1,
alignEnd: {
...r.alignEnd,
},
section: {
flexDirection: "column",
@@ -261,14 +263,14 @@ const useKakunaTemplate = (): KakunaTemplate => {
},
contactList: {
width: "100%",
flexDirection: "row",
flexDirection: r.row,
flexWrap: "wrap",
justifyContent: "center",
rowGap: metrics.gapY(0.125),
columnGap: metrics.gapX(0.75),
},
contactItem: {
flexDirection: "row",
flexDirection: r.row,
alignItems: "center",
columnGap: metrics.gapX(1 / 6),
},
@@ -295,5 +297,5 @@ const useKakunaTemplate = (): KakunaTemplate => {
}),
} satisfies KakunaStyles,
};
}, [picture, metadata]);
}, [picture, metadata, rtl]);
};